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/slave.h"
51 #include "ardour/tempo.h"
52 #include "ardour/operations.h"
53 #include "ardour/vca.h"
54 #include "ardour/vca_manager.h"
59 using namespace ARDOUR;
63 Session::add_post_transport_work (PostTransportWork ptw)
65 PostTransportWork oldval;
66 PostTransportWork newval;
70 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
71 newval = PostTransportWork (oldval | ptw);
72 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
78 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
82 Session::request_sync_source (Slave* new_slave)
84 SessionEvent* ev = new SessionEvent (SessionEvent::SetSyncSource, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
87 seamless = Config->get_seamless_loop ();
89 if (dynamic_cast<Engine_Slave*>(new_slave)) {
90 /* JACK cannot support seamless looping at present */
91 Config->set_seamless_loop (false);
93 /* reset to whatever the value was before we last switched slaves */
94 Config->set_seamless_loop (_was_seamless);
97 /* save value of seamless from before the switch */
98 _was_seamless = seamless;
100 ev->slave = new_slave;
101 DEBUG_TRACE (DEBUG::Slave, "sent request for new slave\n");
106 Session::request_transport_speed (double speed, bool as_default)
108 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
109 ev->third_yes_or_no = as_default; // as_default
110 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
114 /** Request a new transport speed, but if the speed parameter is exactly zero then use
115 * a very small +ve value to prevent the transport actually stopping. This method should
116 * be used by callers who are varying transport speed but don't ever want to stop it.
119 Session::request_transport_speed_nonzero (double speed, bool as_default)
125 request_transport_speed (speed, as_default);
129 Session::request_stop (bool abort, bool clear_state)
131 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
132 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));
137 Session::request_locate (samplepos_t target_sample, bool with_roll)
139 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
140 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
145 Session::force_locate (samplepos_t target_sample, bool with_roll)
147 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
148 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
153 Session::unset_preroll_record_trim ()
155 _preroll_record_trim_len = 0;
159 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
161 if (actively_recording ()) {
164 unset_preroll_record_trim ();
166 config.set_punch_in (false);
167 config.set_punch_out (false);
169 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
170 _preroll_record_trim_len = preroll;
171 maybe_enable_record ();
172 request_locate (pos, true);
173 set_requested_return_sample (rec_in);
177 Session::request_count_in_record ()
179 if (actively_recording ()) {
182 if (transport_rolling()) {
185 maybe_enable_record ();
186 _count_in_once = true;
187 request_transport_speed (1.0, true);
191 Session::request_play_loop (bool yn, bool change_transport_roll)
194 // don't attempt to loop when not using Internal Transport
195 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
200 Location *location = _locations->auto_loop_location();
203 if (location == 0 && yn) {
204 error << _("Cannot loop - no loop range defined")
209 if (change_transport_roll) {
210 if (transport_rolling()) {
211 /* start looping at current speed */
212 target_speed = transport_speed ();
214 /* currently stopped */
216 /* start looping at normal speed */
223 /* leave the speed alone */
224 target_speed = transport_speed ();
227 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn);
228 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
232 if (!change_transport_roll) {
233 if (!transport_rolling()) {
234 /* we're not changing transport state, but we do want
235 to set up position for the new loop. Don't
236 do this if we're rolling already.
238 request_locate (location->start(), false);
242 if (!change_transport_roll && Config->get_seamless_loop() && transport_rolling()) {
243 // request an immediate locate to refresh the tracks
244 // after disabling looping
245 request_locate (_transport_sample-1, false);
251 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
253 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
255 ev->audio_range = *range;
257 ev->audio_range.clear ();
259 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
264 Session::request_cancel_play_range ()
266 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
272 Session::solo_selection_active ()
274 if ( _soloSelection.empty() ) {
281 Session::solo_selection ( StripableList &list, bool new_state )
283 boost::shared_ptr<ControlList> solo_list (new ControlList);
284 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
287 _soloSelection = list;
289 _soloSelection.clear();
291 boost::shared_ptr<RouteList> rl = get_routes();
293 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
295 if ( !(*i)->is_track() ) {
299 boost::shared_ptr<Stripable> s (*i);
301 bool found = (std::find(list.begin(), list.end(), s) != list.end());
302 if ( new_state && found ) {
304 solo_list->push_back (s->solo_control());
306 //must invalidate playlists on selected tracks, so only selected regions get heard
307 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
309 boost::shared_ptr<Playlist> playlist = track->playlist();
311 playlist->ContentsChanged();
315 unsolo_list->push_back (s->solo_control());
319 set_controls (solo_list, 1.0, Controllable::NoGroup);
320 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
324 Session::realtime_stop (bool abort, bool clear_state)
326 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1\n", _transport_sample));
327 PostTransportWork todo = PostTransportWork (0);
329 /* assume that when we start, we'll be moving forwards */
331 if (_transport_speed < 0.0f) {
332 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
333 _default_transport_speed = 1.0;
335 todo = PostTransportWork (todo | PostTransportStop);
340 boost::shared_ptr<RouteList> r = routes.reader ();
342 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
343 (*i)->realtime_handle_transport_stopped ();
346 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
348 /* the duration change is not guaranteed to have happened, but is likely */
350 todo = PostTransportWork (todo | PostTransportDuration);
353 todo = PostTransportWork (todo | PostTransportAbort);
357 todo = PostTransportWork (todo | PostTransportClearSubstate);
361 add_post_transport_work (todo);
364 _clear_event_type (SessionEvent::StopOnce);
365 _clear_event_type (SessionEvent::RangeStop);
366 _clear_event_type (SessionEvent::RangeLocate);
368 //clear our solo-selection, if there is one
369 if ( solo_selection_active() ) {
370 solo_selection ( _soloSelection, false );
373 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
374 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
376 if (clear_state && !Config->get_loop_is_mode()) {
380 reset_slave_state ();
382 _transport_speed = 0;
383 _target_transport_speed = 0;
386 g_atomic_int_set (&_playback_load, 100);
387 g_atomic_int_set (&_capture_load, 100);
389 if (config.get_use_video_sync()) {
390 waiting_for_sync_offset = true;
393 transport_sub_state = 0;
397 Session::realtime_locate ()
399 boost::shared_ptr<RouteList> r = routes.reader ();
400 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
401 (*i)->realtime_locate ();
406 Session::butler_transport_work ()
408 /* Note: this function executes in the butler thread context */
412 PostTransportWork ptw;
413 boost::shared_ptr<RouteList> r = routes.reader ();
416 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
418 ptw = post_transport_work();
420 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1 at %2\n", enum_2_string (ptw), (before = g_get_monotonic_time())));
423 if (ptw & PostTransportLocate) {
425 if (get_play_loop() && !Config->get_seamless_loop()) {
427 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
429 /* this locate might be happening while we are
432 * Non-seamless looping will require a locate (below) that
433 * will reset capture buffers and throw away data.
435 * Rather than first find all tracks and see if they
436 * have outstanding data, just do a flush anyway. It
437 * may be cheaper this way anyway, and is certainly
441 bool more_disk_io_to_do = false;
445 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
451 if (more_disk_io_to_do) {
460 if (ptw & PostTransportAdjustPlaybackBuffering) {
461 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
462 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
464 tr->adjust_playback_buffering ();
465 /* and refill those buffers ... */
467 (*i)->non_realtime_locate (_transport_sample);
469 VCAList v = _vca_manager->vcas ();
470 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
471 (*i)->non_realtime_locate (_transport_sample);
475 if (ptw & PostTransportAdjustCaptureBuffering) {
476 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
477 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
479 tr->adjust_capture_buffering ();
484 if (ptw & PostTransportCurveRealloc) {
485 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
486 (*i)->curve_reallocate();
490 if (ptw & PostTransportSpeed) {
491 non_realtime_set_speed ();
494 if (ptw & PostTransportReverse) {
497 cumulative_rf_motion = 0;
500 /* don't seek if locate will take care of that in non_realtime_stop() */
502 if (!(ptw & PostTransportLocate)) {
503 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
504 (*i)->non_realtime_locate (_transport_sample);
506 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
507 /* new request, stop seeking, and start again */
508 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
512 VCAList v = _vca_manager->vcas ();
513 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
514 (*i)->non_realtime_locate (_transport_sample);
519 if (ptw & PostTransportLocate) {
520 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
521 non_realtime_locate ();
524 if (ptw & PostTransportStop) {
525 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
527 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
532 if (ptw & PostTransportOverWrite) {
533 non_realtime_overwrite (on_entry, finished);
535 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
540 if (ptw & PostTransportAudition) {
541 non_realtime_set_audition ();
544 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
546 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()));
550 Session::non_realtime_set_speed ()
552 boost::shared_ptr<RouteList> rl = routes.reader();
553 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
554 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
556 tr->non_realtime_speed_change ();
562 Session::non_realtime_overwrite (int on_entry, bool& finished)
564 boost::shared_ptr<RouteList> rl = routes.reader();
565 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
566 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
567 if (tr && tr->pending_overwrite ()) {
568 tr->overwrite_existing_buffers ();
570 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
579 Session::non_realtime_locate ()
581 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
583 if (Config->get_loop_is_mode() && get_play_loop()) {
585 Location *loc = _locations->auto_loop_location();
587 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
588 /* jumped out of loop range: stop tracks from looping,
589 but leave loop (mode) enabled.
591 set_track_loop (false);
593 } else if (loc && Config->get_seamless_loop() &&
594 ((loc->start() <= _transport_sample) ||
595 (loc->end() > _transport_sample) ) ) {
597 /* jumping to start of loop. This might have been done before but it is
598 * idempotent and cheap. Doing it here ensures that when we start playback
599 * outside the loop we still flip tracks into the magic seamless mode
602 set_track_loop (true);
605 set_track_loop (false);
610 /* no more looping .. should have been noticed elsewhere */
617 boost::shared_ptr<RouteList> rl = routes.reader();
620 gint sc = g_atomic_int_get (&_seek_counter);
621 tf = _transport_sample;
623 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
624 (*i)->non_realtime_locate (tf);
625 if (sc != g_atomic_int_get (&_seek_counter)) {
632 /* VCAs are quick to locate because they have no data (except
633 automation) associated with them. Don't bother with a
634 restart mechanism here, but do use the same transport sample
635 that the Routes used.
637 VCAList v = _vca_manager->vcas ();
638 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
639 (*i)->non_realtime_locate (tf);
643 _scene_changer->locate (_transport_sample);
645 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
646 rather than clearing them so that the RT thread has to spend time constructing
647 them (in Session::click).
652 #ifdef USE_TRACKS_CODE_FEATURES
654 Session::select_playhead_priority_target (samplepos_t& jump_to)
658 AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
664 if (Profile->get_trx() && transport_rolling() ) {
665 // We're playing, so do nothing.
666 // Next stop will put us where we need to be.
670 /* Note that the order of checking each AutoReturnTarget flag defines
671 the priority each flag.
673 Ardour/Mixbus: Last Locate
678 Tracks: Range Selection
684 if (autoreturn & RangeSelectionStart) {
685 if (!_range_selection.empty()) {
686 jump_to = _range_selection.from;
688 if (transport_rolling ()) {
689 /* Range selection no longer exists, but we're playing,
690 so do nothing. Next stop will put us where
698 if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
699 /* don't try to handle loop play when synced to JACK */
701 if (!synced_to_engine()) {
702 Location *location = _locations->auto_loop_location();
705 jump_to = location->start();
707 if (Config->get_seamless_loop()) {
708 /* need to get track buffers reloaded */
709 set_track_loop (true);
715 if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
716 if (!_object_selection.empty()) {
717 jump_to = _object_selection.from;
721 if (jump_to < 0 && (autoreturn & LastLocate)) {
722 jump_to = _last_roll_location;
730 Session::select_playhead_priority_target (samplepos_t& jump_to)
732 if (config.get_external_sync() || !config.get_auto_return()) {
736 jump_to = _last_roll_location;
743 Session::follow_playhead_priority ()
747 if (select_playhead_priority_target (target)) {
748 request_locate (target);
753 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
759 PostTransportWork ptw = post_transport_work();
764 boost::shared_ptr<RouteList> rl = routes.reader();
765 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
766 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
767 if (tr && tr->get_captured_samples () != 0) {
773 /* stop and locate are merged here because they share a lot of common stuff */
776 now = localtime (&xnow);
779 auditioner->cancel_audition ();
782 cumulative_rf_motion = 0;
786 begin_reversible_command (Operations::capture);
787 _have_captured = true;
790 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
792 if (abort && did_record) {
793 /* no reason to save the session file when we remove sources
795 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
798 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
799 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
801 tr->transport_stopped_wallclock (*now, xnow, abort);
805 if (abort && did_record) {
806 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
809 boost::shared_ptr<RouteList> r = routes.reader ();
812 commit_reversible_command ();
813 /* increase take name */
814 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
815 string newname = config.get_take_name();
816 config.set_take_name(bump_name_number (newname));
820 if (_engine.running()) {
821 PostTransportWork ptw = post_transport_work ();
823 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
824 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
826 VCAList v = _vca_manager->vcas ();
827 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
828 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
831 update_latency_compensation ();
834 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
836 if (auto_return_enabled ||
837 (ptw & PostTransportLocate) ||
838 (_requested_return_sample >= 0) ||
839 synced_to_engine()) {
841 // rg: what is the logic behind this case?
842 // _requested_return_sample should be ignored when synced_to_engine/slaved.
843 // currently worked around in MTC_Slave by forcing _requested_return_sample to -1
845 if ((auto_return_enabled || synced_to_engine() || _requested_return_sample >= 0) &&
846 !(ptw & PostTransportLocate)) {
848 /* no explicit locate queued */
850 bool do_locate = false;
852 if (_requested_return_sample >= 0) {
854 /* explicit return request pre-queued in event list. overrides everything else */
856 _transport_sample = _requested_return_sample;
862 if (select_playhead_priority_target (jump_to)) {
864 _transport_sample = jump_to;
869 _transport_sample = _last_roll_location;
874 _requested_return_sample = -1;
877 _engine.transport_locate (_transport_sample);
884 unset_preroll_record_trim ();
886 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
889 if (ptw & PostTransportClearSubstate) {
891 if (!Config->get_loop_is_mode()) {
896 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
899 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
900 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
901 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
902 (*i)->non_realtime_locate (_transport_sample);
904 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
906 /* we will be back */
913 VCAList v = _vca_manager->vcas ();
914 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
915 (*i)->non_realtime_locate (_transport_sample);
921 /* don't bother with this stuff if we're disconnected from the engine,
922 because there will be no process callbacks to deliver stuff from
925 if (_engine.connected() && !_engine.freewheeling()) {
926 // need to queue this in the next RT cycle
927 _send_timecode_update = true;
929 if (!dynamic_cast<MTC_Slave*>(_slave)) {
930 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
932 /* This (::non_realtime_stop()) gets called by main
933 process thread, which will lead to confusion
934 when calling AsyncMIDIPort::write().
936 Something must be done. XXX
938 send_mmc_locate (_transport_sample);
942 if ((ptw & PostTransportLocate) && get_record_enabled()) {
943 /* This is scheduled by realtime_stop(), which is also done
944 * when a slave requests /locate/ for an initial sync.
945 * We can't hold up the slave for long with a save() here,
946 * without breaking its initial sync cycle.
948 * save state only if there's no slave or if it's not yet locked.
950 if (!_slave || !_slave->locked()) {
951 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
952 SaveSessionRequested (_current_snapshot_name);
957 /* always try to get rid of this */
959 remove_pending_capture_state ();
961 /* save the current state of things if appropriate */
963 if (did_record && !saved) {
964 SaveSessionRequested (_current_snapshot_name);
967 if (ptw & PostTransportStop) {
969 if (!Config->get_loop_is_mode()) {
974 PositionChanged (_transport_sample); /* EMIT SIGNAL */
975 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
976 TransportStateChange (); /* EMIT SIGNAL */
977 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
979 /* and start it up again if relevant */
981 if ((ptw & PostTransportLocate) && !config.get_external_sync()) {
982 request_transport_speed (1.0);
987 Session::unset_play_loop ()
991 clear_events (SessionEvent::AutoLoop);
992 set_track_loop (false);
995 if (Config->get_seamless_loop()) {
996 /* likely need to flush track buffers: this will locate us to wherever we are */
997 add_post_transport_work (PostTransportLocate);
998 _butler->schedule_transport_work ();
1004 Session::set_track_loop (bool yn)
1006 Location* loc = _locations->auto_loop_location ();
1012 boost::shared_ptr<RouteList> rl = routes.reader ();
1014 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1015 if (*i && !(*i)->is_private_route()) {
1016 (*i)->set_loop (yn ? loc : 0);
1022 Session::set_play_loop (bool yn, double speed)
1024 /* Called from event-handling context */
1028 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1029 /* nothing to do, or can't change loop status while recording */
1033 if (yn && Config->get_seamless_loop() && synced_to_engine()) {
1034 warning << string_compose (
1035 _("Seamless looping cannot be supported while %1 is using JACK transport.\n"
1036 "Recommend changing the configured options"), PROGRAM_NAME)
1044 have_looped = false;
1048 unset_play_range ();
1050 if (Config->get_seamless_loop()) {
1051 if (!Config->get_loop_is_mode()) {
1052 /* set all tracks to use internal looping */
1053 set_track_loop (true);
1055 /* we will do this in the locate to the start OR when we hit the end
1056 * of the loop for the first time
1060 /* set all tracks to NOT use internal looping */
1061 set_track_loop (false);
1064 /* Put the delick and loop events in into the event list. The declick event will
1065 cause a de-clicking fade-out just before the end of the loop, and it will also result
1066 in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
1071 auto_loop_declick_range (loc, dcp, dcl);
1072 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1074 /* if requested to roll, locate to start of loop and
1075 * roll but ONLY if we're not already rolling.
1077 args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
1080 if (Config->get_loop_is_mode()) {
1081 /* loop IS a transport mode: if already
1082 rolling, do not locate to loop start.
1084 if (!transport_rolling() && (speed != 0.0)) {
1085 start_locate (loc->start(), true, true, false, true);
1089 start_locate (loc->start(), true, true, false, true);
1099 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
1100 TransportStateChange ();
1103 Session::flush_all_inserts ()
1105 boost::shared_ptr<RouteList> r = routes.reader ();
1107 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1108 (*i)->flush_processors ();
1113 Session::start_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force)
1115 if (target_sample < 0) {
1116 error << _("Locate called for negative sample position - ignored") << endmsg;
1120 if (synced_to_engine()) {
1125 _slave->speed_and_position (sp, pos);
1127 if (target_sample != pos) {
1129 if (config.get_jack_time_master()) {
1130 /* actually locate now, since otherwise jack_timebase_callback
1131 will use the incorrect _transport_sample and report an old
1132 and incorrect time to Jack transport
1134 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1137 /* tell JACK to change transport position, and we will
1138 follow along later in ::follow_slave()
1141 _engine.transport_locate (target_sample);
1143 if (sp != 1.0f && with_roll) {
1144 _engine.transport_start ();
1150 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1155 Session::worst_latency_preroll () const
1157 return _worst_output_latency + _worst_input_latency;
1161 Session::micro_locate (samplecnt_t distance)
1163 boost::shared_ptr<RouteList> rl = routes.reader();
1164 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1165 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1166 if (tr && !tr->can_internal_playback_seek (distance)) {
1171 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1172 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1174 tr->internal_playback_seek (distance);
1178 _transport_sample += distance;
1182 /** @param with_mmc true to send a MMC locate command when the locate is done */
1184 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
1186 bool need_butler = false;
1188 /* Locates for seamless looping are fairly different from other
1189 * locates. They assume that the diskstream buffers for each track
1190 * already have the correct data in them, and thus there is no need to
1191 * actually tell the tracks to locate. What does need to be done,
1192 * though, is all the housekeeping that is associated with non-linear
1193 * changes in the value of _transport_sample.
1196 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
1197 target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc));
1199 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_enabled) {
1201 /* already at the desired position. Not forced to locate,
1202 the loop isn't changing, so unless we're told to
1203 start rolling also, there's nothing to do but
1204 tell the world where we are (again).
1208 set_transport_speed (1.0, 0, false);
1210 loop_changing = false;
1211 Located (); /* EMIT SIGNAL */
1215 cerr << "... now doing the actual locate\n";
1217 // Update Timecode time
1218 _transport_sample = target_sample;
1219 // Bump seek counter so that any in-process locate in the butler
1220 // thread(s?) can restart.
1221 g_atomic_int_inc (&_seek_counter);
1222 _last_roll_or_reversal_location = target_sample;
1223 _remaining_latency_preroll = worst_latency_preroll ();
1224 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
1226 /* do "stopped" stuff if:
1228 * we are rolling AND
1229 * no autoplay in effect AND
1230 * we're not going to keep rolling after the locate AND
1231 * !(playing a loop with JACK sync)
1235 bool transport_was_stopped = !transport_rolling();
1237 if (!transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
1238 (!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
1239 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
1240 transport_was_stopped = true;
1242 /* otherwise tell the world that we located */
1246 if (force || !for_loop_enabled || loop_changing) {
1248 PostTransportWork todo = PostTransportLocate;
1250 if (with_roll && transport_was_stopped) {
1251 todo = PostTransportWork (todo | PostTransportRoll);
1254 add_post_transport_work (todo);
1259 /* this is functionally what clear_clicks() does but with a tentative lock */
1261 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
1263 if (clickm.locked()) {
1265 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
1274 /* switch from input if we're going to roll */
1275 if (Config->get_monitoring_model() == HardwareMonitoring) {
1276 set_track_monitor_input_status (!config.get_auto_input());
1279 /* otherwise we're going to stop, so do the opposite */
1280 if (Config->get_monitoring_model() == HardwareMonitoring) {
1281 set_track_monitor_input_status (true);
1285 /* cancel looped playback if transport pos outside of loop range */
1288 Location* al = _locations->auto_loop_location();
1291 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
1293 // located outside the loop: cancel looping directly, this is called from event handling context
1295 have_looped = false;
1297 if (!Config->get_loop_is_mode()) {
1298 set_play_loop (false, _transport_speed);
1300 if (Config->get_seamless_loop()) {
1301 /* this will make the non_realtime_locate() in the butler
1302 which then causes seek() in tracks actually do the right
1305 set_track_loop (false);
1309 } else if (_transport_sample == al->start()) {
1311 // located to start of loop - this is looping, basically
1315 if (_last_roll_location != al->start()) {
1316 /* didn't start at loop start - playback must have
1317 * started before loop since we've now hit the loop
1320 add_post_transport_work (PostTransportLocate);
1326 boost::shared_ptr<RouteList> rl = routes.reader();
1328 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1329 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1331 if (tr && tr->rec_enable_control()->get_value()) {
1332 // tell it we've looped, so it can deal with the record state
1333 tr->transport_looped (_transport_sample);
1338 TransportLooped(); // EMIT SIGNAL
1344 _butler->schedule_transport_work ();
1347 loop_changing = false;
1349 _send_timecode_update = true;
1352 send_mmc_locate (_transport_sample);
1355 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
1356 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
1357 Located (); /* EMIT SIGNAL */
1361 /** Set the transport speed.
1362 * Called from the process thread.
1363 * @param speed New speed
1366 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
1368 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
1369 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
1371 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
1372 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
1376 speed = min (8.0, speed);
1377 } else if (speed < 0) {
1378 speed = max (-8.0, speed);
1381 double new_engine_speed = 1.0;
1383 new_engine_speed = fabs (speed);
1384 if (speed < 0) speed = -1;
1385 if (speed > 0) speed = 1;
1388 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
1389 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
1390 _default_transport_speed = 1.0;
1395 #if 0 // TODO pref: allow vari-speed recording
1396 if (actively_recording() && speed != 1.0 && speed != 0.0) {
1397 /* no varispeed during recording */
1398 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
1399 _transport_speed, _transport_sample));
1404 _target_transport_speed = fabs(speed);
1405 _engine_speed = new_engine_speed;
1407 if (transport_rolling() && speed == 0.0) {
1409 /* we are rolling and we want to stop */
1411 if (Config->get_monitoring_model() == HardwareMonitoring) {
1412 set_track_monitor_input_status (true);
1415 if (synced_to_engine ()) {
1417 /* do this here because our response to the slave won't
1420 _play_range = false;
1421 _count_in_once = false;
1424 _engine.transport_stop ();
1426 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
1428 if (!auto_return_enabled) {
1429 _requested_return_sample = destination_sample;
1432 stop_transport (abort);
1435 } else if (transport_stopped() && speed == 1.0) {
1437 _default_transport_speed = speed;
1439 /* we are stopped and we want to start rolling at speed 1 */
1441 if (Config->get_loop_is_mode() && play_loop) {
1443 Location *location = _locations->auto_loop_location();
1445 if (location != 0) {
1446 if (_transport_sample != location->start()) {
1448 if (Config->get_seamless_loop()) {
1449 /* force tracks to do their thing */
1450 set_track_loop (true);
1453 /* jump to start and then roll from there */
1455 request_locate (location->start(), true);
1461 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
1462 set_track_monitor_input_status (false);
1465 if (synced_to_engine()) {
1466 _engine.transport_start ();
1467 _count_in_once = false;
1474 /* not zero, not 1.0 ... varispeed */
1476 // TODO handled transport start.. _remaining_latency_preroll
1477 // and reversal of playback direction.
1479 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
1480 warning << string_compose (
1481 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
1488 if (actively_recording()) {
1493 if (speed > 0.0 && _transport_sample == current_end_sample()) {
1497 if (speed < 0.0 && _transport_sample == 0) {
1503 /* if we are reversing relative to the current speed, or relative to the speed
1504 before the last stop, then we have to do extra work.
1507 PostTransportWork todo = PostTransportWork (0);
1509 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
1510 todo = PostTransportWork (todo | PostTransportReverse);
1511 _last_roll_or_reversal_location = _transport_sample;
1514 _last_transport_speed = _transport_speed;
1515 _transport_speed = speed;
1518 _default_transport_speed = speed;
1522 add_post_transport_work (todo);
1523 _butler->schedule_transport_work ();
1526 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
1528 /* throttle signal emissions.
1529 * when slaved [_last]_transport_speed
1530 * usually changes every cycle (tiny amounts due to DLL).
1531 * Emitting a signal every cycle is overkill and unwarranted.
1533 * Using _last_transport_speed is not acceptable,
1534 * since it allows for large changes over a long period
1535 * of time. Hence we introduce a dedicated variable to keep track
1537 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
1538 * for TransportStateChange() here is the ShuttleControl display.
1540 if (fabs (_signalled_varispeed - actual_speed ()) > .002
1541 // still, signal hard changes to 1.0 and 0.0:
1542 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
1543 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
1546 TransportStateChange (); /* EMIT SIGNAL */
1547 _signalled_varispeed = actual_speed ();
1553 /** Stop the transport. */
1555 Session::stop_transport (bool abort, bool clear_state)
1557 _count_in_once = false;
1558 if (_transport_speed == 0.0f) {
1562 DEBUG_TRACE (DEBUG::Transport, "time to actually stop\n");
1564 realtime_stop (abort, clear_state);
1565 _butler->schedule_transport_work ();
1568 /** Called from the process thread */
1570 Session::start_transport ()
1572 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
1574 _last_roll_location = _transport_sample;
1575 _last_roll_or_reversal_location = _transport_sample;
1576 _remaining_latency_preroll = worst_latency_preroll ();
1578 have_looped = false;
1580 /* if record status is Enabled, move it to Recording. if its
1581 already Recording, move it to Disabled.
1584 switch (record_status()) {
1586 if (!config.get_punch_in()) {
1587 /* This is only for UIs (keep blinking rec-en before
1588 * punch-in, don't show rec-region etc). The UI still
1589 * depends on SessionEvent::PunchIn and ensuing signals.
1591 * The disk-writers handle punch in/out internally
1592 * in their local delay-compensated timeframe.
1600 disable_record (false);
1608 _transport_speed = _default_transport_speed;
1609 _target_transport_speed = _transport_speed;
1611 if (!_engine.freewheeling()) {
1612 Timecode::Time time;
1613 timecode_time_subframes (_transport_sample, time);
1614 if (!dynamic_cast<MTC_Slave*>(_slave)) {
1615 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
1618 if (actively_recording() && click_data && (config.get_count_in () || _count_in_once)) {
1619 _count_in_once = false;
1620 /* calculate count-in duration (in audio samples)
1621 * - use [fixed] tempo/meter at _transport_sample
1622 * - calc duration of 1 bar + time-to-beat before or at transport_sample
1624 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
1625 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
1627 const double num = meter.divisions_per_bar ();
1628 const double den = meter.note_divisor ();
1629 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
1630 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
1632 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
1634 double dt = _count_in_samples / num;
1635 if (bar_fract == 0) {
1636 /* at bar boundary, count-in 2 bars before start. */
1637 _count_in_samples *= 2;
1639 /* beats left after full bar until roll position */
1640 _count_in_samples *= 1. + bar_fract;
1643 if (_count_in_samples > _remaining_latency_preroll) {
1644 _remaining_latency_preroll = _count_in_samples;
1648 samplepos_t cf = _transport_sample - _count_in_samples;
1649 samplecnt_t offset = _click_io->connected_latency (true);
1650 while (cf < _transport_sample + offset) {
1651 add_click (cf, clickbeat == 0);
1653 clickbeat = fmod (clickbeat + 1, num);
1656 if (_count_in_samples < _remaining_latency_preroll) {
1657 _count_in_samples = _remaining_latency_preroll;
1662 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
1663 TransportStateChange (); /* EMIT SIGNAL */
1666 /** Do any transport work in the audio thread that needs to be done after the
1667 * transport thread is finished. Audio thread, realtime safe.
1670 Session::post_transport ()
1672 PostTransportWork ptw = post_transport_work ();
1674 if (ptw & PostTransportAudition) {
1675 if (auditioner && auditioner->auditioning()) {
1676 process_function = &Session::process_audition;
1678 process_function = &Session::process_with_events;
1682 if (ptw & PostTransportStop) {
1684 transport_sub_state = 0;
1687 if (ptw & PostTransportLocate) {
1689 if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
1690 _count_in_once = false;
1693 transport_sub_state = 0;
1698 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
1701 set_post_transport_work (PostTransportWork (0));
1705 Session::reset_rf_scale (samplecnt_t motion)
1707 cumulative_rf_motion += motion;
1709 if (cumulative_rf_motion < 4 * _current_sample_rate) {
1711 } else if (cumulative_rf_motion < 8 * _current_sample_rate) {
1713 } else if (cumulative_rf_motion < 16 * _current_sample_rate) {
1725 Session::mtc_status_changed (bool yn)
1727 g_atomic_int_set (&_mtc_active, yn);
1728 MTCSyncStateChanged( yn );
1732 Session::ltc_status_changed (bool yn)
1734 g_atomic_int_set (&_ltc_active, yn);
1735 LTCSyncStateChanged( yn );
1739 Session::use_sync_source (Slave* new_slave)
1741 /* Runs in process() context */
1743 bool non_rt_required = false;
1745 /* XXX this deletion is problematic because we're in RT context */
1751 /* slave change, reset any DiskIO block on disk output because it is no
1752 longer valid with a new slave.
1754 DiskReader::set_no_disk_output (false);
1756 MTC_Slave* mtc_slave = dynamic_cast<MTC_Slave*>(_slave);
1758 mtc_slave->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
1759 MTCSyncStateChanged(mtc_slave->locked() );
1761 if (g_atomic_int_get (&_mtc_active) ){
1762 g_atomic_int_set (&_mtc_active, 0);
1763 MTCSyncStateChanged( false );
1765 mtc_status_connection.disconnect ();
1768 LTC_Slave* ltc_slave = dynamic_cast<LTC_Slave*> (_slave);
1770 ltc_slave->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
1771 LTCSyncStateChanged (ltc_slave->locked() );
1773 if (g_atomic_int_get (&_ltc_active) ){
1774 g_atomic_int_set (&_ltc_active, 0);
1775 LTCSyncStateChanged( false );
1777 ltc_status_connection.disconnect ();
1780 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave));
1782 // need to queue this for next process() cycle
1783 _send_timecode_update = true;
1785 boost::shared_ptr<RouteList> rl = routes.reader();
1786 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1787 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1788 if (tr && !tr->is_private_route()) {
1789 tr->set_slaved (_slave != 0);
1793 if (non_rt_required) {
1794 add_post_transport_work (PostTransportSpeed);
1795 _butler->schedule_transport_work ();
1802 Session::drop_sync_source ()
1804 request_sync_source (0);
1808 Session::switch_to_sync_source (SyncSource src)
1812 DEBUG_TRACE (DEBUG::Slave, string_compose ("Setting up sync source %1\n", enum_2_string (src)));
1816 if (_slave && dynamic_cast<MTC_Slave*>(_slave)) {
1821 new_slave = new MTC_Slave (*this, *_midi_ports->mtc_input_port());
1824 catch (failed_constructor& err) {
1830 if (_slave && dynamic_cast<LTC_Slave*>(_slave)) {
1835 new_slave = new LTC_Slave (*this);
1838 catch (failed_constructor& err) {
1845 if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
1850 new_slave = new MIDIClock_Slave (*this, *_midi_ports->midi_clock_input_port(), 24);
1853 catch (failed_constructor& err) {
1859 if (_slave && dynamic_cast<Engine_Slave*>(_slave)) {
1863 if (config.get_video_pullup() != 0.0f) {
1867 new_slave = new Engine_Slave (*AudioEngine::instance());
1875 request_sync_source (new_slave);
1879 Session::unset_play_range ()
1881 _play_range = false;
1882 _clear_event_type (SessionEvent::RangeStop);
1883 _clear_event_type (SessionEvent::RangeLocate);
1887 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1891 /* Called from event-processing context */
1893 unset_play_range ();
1895 if (range.empty()) {
1896 /* _play_range set to false in unset_play_range()
1898 if (!leave_rolling) {
1899 /* stop transport */
1900 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1908 /* cancel loop play */
1911 list<AudioRange>::size_type sz = range.size();
1915 list<AudioRange>::iterator i = range.begin();
1916 list<AudioRange>::iterator next;
1918 while (i != range.end()) {
1923 /* locating/stopping is subject to delays for declicking.
1926 samplepos_t requested_sample = i->end;
1928 if (requested_sample > current_block_size) {
1929 requested_sample -= current_block_size;
1931 requested_sample = 0;
1934 if (next == range.end()) {
1935 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1937 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1945 } else if (sz == 1) {
1947 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1952 /* save range so we can do auto-return etc. */
1954 current_audio_range = range;
1956 /* now start rolling at the right place */
1958 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1961 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1962 TransportStateChange ();
1966 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1968 AudioRange ar (start, end, 0);
1969 list<AudioRange> lar;
1972 request_play_range (&lar, true);
1976 Session::set_requested_return_sample (samplepos_t return_to)
1978 _requested_return_sample = return_to;
1982 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1984 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1985 ev->target2_sample = start;
1990 Session::engine_halted ()
1994 /* there will be no more calls to process(), so
1995 we'd better clean up for ourselves, right now.
1997 but first, make sure the butler is out of
2005 realtime_stop (false, true);
2006 non_realtime_stop (false, 0, ignored);
2007 transport_sub_state = 0;
2009 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC6 with speed = %1\n", _transport_speed));
2010 TransportStateChange (); /* EMIT SIGNAL */
2015 Session::xrun_recovery ()
2019 Xrun (_transport_sample); /* EMIT SIGNAL */
2021 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
2023 /* it didn't actually halt, but we need
2024 to handle things in the same way.
2032 Session::route_processors_changed (RouteProcessorChange c)
2034 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
2038 if (c.type == RouteProcessorChange::MeterPointChange) {
2043 if (c.type == RouteProcessorChange::RealTimeChange) {
2048 update_latency_compensation ();
2055 Session::allow_auto_play (bool yn)
2057 auto_play_legal = yn;
2061 Session::maybe_stop (samplepos_t limit)
2063 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
2064 if (synced_to_engine () && config.get_jack_time_master ()) {
2065 _engine.transport_stop ();
2066 } else if (!synced_to_engine ()) {
2075 Session::send_mmc_locate (samplepos_t t)
2081 if (!_engine.freewheeling()) {
2082 Timecode::Time time;
2083 timecode_time_subframes (t, time);
2084 send_immediate_mmc (MIDI::MachineControlCommand (time));
2088 /** Ask the transport to not send timecode until further notice. The suspension
2089 * will come into effect some finite time after this call, and timecode_transmission_suspended()
2090 * should be checked by the caller to find out when.
2093 Session::request_suspend_timecode_transmission ()
2095 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
2100 Session::request_resume_timecode_transmission ()
2102 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
2107 Session::timecode_transmission_suspended () const
2109 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;