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.
26 #include "pbd/error.h"
27 #include "pbd/enumwriter.h"
28 #include "pbd/pthread_utils.h"
29 #include "pbd/memento_command.h"
31 #include "midi++/mmc.h"
32 #include "midi++/port.h"
33 #include "midi++/manager.h"
35 #include "ardour/ardour.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/auditioner.h"
38 #include "ardour/butler.h"
39 #include "ardour/debug.h"
40 #include "ardour/location.h"
41 #include "ardour/session.h"
42 #include "ardour/slave.h"
47 using namespace ARDOUR;
51 Session::add_post_transport_work (PostTransportWork ptw)
53 PostTransportWork oldval;
54 PostTransportWork newval;
58 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
59 newval = PostTransportWork (oldval | ptw);
60 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
66 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
70 Session::request_input_change_handling ()
72 if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
73 SessionEvent* ev = new SessionEvent (SessionEvent::InputConfigurationChange, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
79 Session::request_sync_source (Slave* new_slave)
81 SessionEvent* ev = new SessionEvent (SessionEvent::SetSyncSource, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
84 seamless = Config->get_seamless_loop ();
86 if (dynamic_cast<JACK_Slave*>(new_slave)) {
87 /* JACK cannot support seamless looping at present */
88 Config->set_seamless_loop (false);
90 /* reset to whatever the value was before we last switched slaves */
91 Config->set_seamless_loop (_was_seamless);
94 /* save value of seamless from before the switch */
95 _was_seamless = seamless;
97 ev->slave = new_slave;
102 Session::request_transport_speed (double speed)
104 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
105 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1\n", speed));
110 Session::request_track_speed (Track* tr, double speed)
112 SessionEvent* ev = new SessionEvent (SessionEvent::SetTrackSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
118 Session::request_stop (bool abort, bool clear_state)
120 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0, abort, clear_state);
121 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport stop, abort = %1, clear state = %2\n", abort, clear_state));
126 Session::request_locate (nframes_t target_frame, bool with_roll)
128 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, false);
129 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_frame));
134 Session::force_locate (nframes64_t target_frame, bool with_roll)
136 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, true);
137 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_frame));
142 Session::request_play_loop (bool yn, bool leave_rolling)
145 Location *location = _locations->auto_loop_location();
147 if (location == 0 && yn) {
148 error << _("Cannot loop - no loop range defined")
153 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0), yn);
154 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, leave rolling ? %2\n", yn, leave_rolling));
157 if (!leave_rolling && !yn && Config->get_seamless_loop() && transport_rolling()) {
158 // request an immediate locate to refresh the tracks
159 // after disabling looping
160 request_locate (_transport_frame-1, false);
165 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
167 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
169 ev->audio_range = *range;
171 ev->audio_range.clear ();
173 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
178 Session::realtime_stop (bool abort, bool clear_state)
180 DEBUG_TRACE (DEBUG::Transport, "realtime stop\n");
181 PostTransportWork todo = PostTransportWork (0);
183 /* assume that when we start, we'll be moving forwards */
185 if (_transport_speed < 0.0f) {
186 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
188 todo = PostTransportWork (todo | PostTransportStop);
191 if (actively_recording()) {
193 /* move the transport position back to where the
194 request for a stop was noticed. we rolled
195 past that point to pick up delayed input (and/or to delick)
198 if (_worst_output_latency > current_block_size) {
199 /* we rolled past the stop point to pick up data that had
200 not yet arrived. move back to where the stop occured.
202 decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size));
204 decrement_transport_position (current_block_size);
207 /* the duration change is not guaranteed to have happened, but is likely */
209 todo = PostTransportWork (todo | PostTransportDuration);
213 todo = PostTransportWork (todo | PostTransportAbort);
217 todo = PostTransportWork (todo | PostTransportClearSubstate);
221 add_post_transport_work (todo);
224 _clear_event_type (SessionEvent::StopOnce);
225 _clear_event_type (SessionEvent::RangeStop);
226 _clear_event_type (SessionEvent::RangeLocate);
228 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
229 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
231 reset_slave_state ();
233 _transport_speed = 0;
234 _target_transport_speed = 0;
236 g_atomic_int_set (&_playback_load, 100);
237 g_atomic_int_set (&_capture_load, 100);
239 if (config.get_use_video_sync()) {
240 waiting_for_sync_offset = true;
243 transport_sub_state = 0;
247 Session::butler_transport_work ()
251 PostTransportWork ptw;
252 boost::shared_ptr<RouteList> r = routes.reader ();
254 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
256 ptw = post_transport_work();
258 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1\n", enum_2_string (ptw)));
260 if (ptw & PostTransportAdjustPlaybackBuffering) {
261 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
262 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
264 tr->adjust_playback_buffering ();
265 /* and refill those buffers ... */
266 tr->non_realtime_locate (_transport_frame);
272 if (ptw & PostTransportAdjustCaptureBuffering) {
273 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
274 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
276 tr->adjust_capture_buffering ();
281 if (ptw & PostTransportCurveRealloc) {
282 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
283 (*i)->curve_reallocate();
287 if (ptw & PostTransportInputChange) {
288 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
289 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
291 tr->non_realtime_input_change ();
296 if (ptw & PostTransportSpeed) {
297 non_realtime_set_speed ();
300 if (ptw & PostTransportReverse) {
303 cumulative_rf_motion = 0;
306 /* don't seek if locate will take care of that in non_realtime_stop() */
308 if (!(ptw & PostTransportLocate)) {
310 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
311 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
312 if (tr && !tr->hidden()) {
313 tr->non_realtime_locate (_transport_frame);
315 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
316 /* new request, stop seeking, and start again */
317 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
324 if (ptw & PostTransportLocate) {
325 non_realtime_locate ();
328 if (ptw & PostTransportStop) {
329 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
331 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
336 if (ptw & PostTransportOverWrite) {
337 non_realtime_overwrite (on_entry, finished);
339 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
344 if (ptw & PostTransportAudition) {
345 non_realtime_set_audition ();
348 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
350 DEBUG_TRACE (DEBUG::Transport, X_("Butler transport work all done\n"));
354 Session::non_realtime_set_speed ()
356 boost::shared_ptr<RouteList> rl = routes.reader();
357 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
358 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
360 tr->non_realtime_set_speed ();
366 Session::non_realtime_overwrite (int on_entry, bool& finished)
368 boost::shared_ptr<RouteList> rl = routes.reader();
369 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
370 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
371 if (tr && tr->pending_overwrite ()) {
372 tr->overwrite_existing_buffers ();
374 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
383 Session::non_realtime_locate ()
385 boost::shared_ptr<RouteList> rl = routes.reader();
386 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
387 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
389 tr->non_realtime_locate (_transport_frame);
396 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
402 PostTransportWork ptw = post_transport_work();
407 boost::shared_ptr<RouteList> rl = routes.reader();
408 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
409 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
410 if (tr && tr->get_captured_frames () != 0) {
416 /* stop and locate are merged here because they share a lot of common stuff */
419 now = localtime (&xnow);
422 auditioner->cancel_audition ();
426 cumulative_rf_motion = 0;
430 begin_reversible_command ("capture");
431 _have_captured = true;
434 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
436 if (abort && did_record) {
437 /* no reason to save the session file when we remove sources
439 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
442 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
443 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
445 tr->transport_stopped_wallclock (*now, xnow, abort);
449 if (abort && did_record) {
450 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
453 boost::shared_ptr<RouteList> r = routes.reader ();
455 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
456 if (!(*i)->is_hidden()) {
457 (*i)->set_pending_declick (0);
462 commit_reversible_command ();
465 if (_engine.running()) {
466 update_latency_compensation (true, abort);
469 bool const auto_return_enabled =
470 (!config.get_external_sync() && config.get_auto_return());
472 if (auto_return_enabled ||
473 (ptw & PostTransportLocate) ||
474 (_requested_return_frame >= 0) ||
477 if (pending_locate_flush) {
478 flush_all_inserts ();
481 if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) &&
482 !(ptw & PostTransportLocate)) {
484 /* no explicit locate queued */
486 bool do_locate = false;
488 if (_requested_return_frame >= 0) {
490 /* explicit return request pre-queued in event list. overrides everything else */
492 cerr << "explicit auto-return to " << _requested_return_frame << endl;
494 _transport_frame = _requested_return_frame;
498 if (config.get_auto_return()) {
502 /* don't try to handle loop play when synced to JACK */
504 if (!synced_to_jack()) {
506 Location *location = _locations->auto_loop_location();
509 _transport_frame = location->start();
511 _transport_frame = _last_roll_location;
516 } else if (_play_range) {
518 /* return to start of range */
520 if (!current_audio_range.empty()) {
521 _transport_frame = current_audio_range.front().start;
527 /* regular auto-return */
529 _transport_frame = _last_roll_location;
535 _requested_return_frame = -1;
538 _engine.transport_locate (_transport_frame);
544 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
547 if (ptw & PostTransportClearSubstate) {
552 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
554 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
555 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
556 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
557 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
558 if (tr && !tr->hidden()) {
559 tr->non_realtime_locate (_transport_frame);
562 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
564 /* we will be back */
571 send_full_time_code (_transport_frame);
572 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
573 send_mmc_locate (_transport_frame);
575 if ((ptw & PostTransportLocate) && get_record_enabled()) {
576 /* capture start has been changed, so save pending state */
577 save_state ("", true);
581 /* always try to get rid of this */
583 remove_pending_capture_state ();
585 /* save the current state of things if appropriate */
587 if (did_record && !saved) {
588 save_state (_current_snapshot_name);
591 if (ptw & PostTransportStop) {
596 // can't cast away volatile so copy and emit that
597 nframes64_t tframe = _transport_frame;
598 PositionChanged (tframe); /* EMIT SIGNAL */
599 TransportStateChange (); /* EMIT SIGNAL */
601 /* and start it up again if relevant */
603 if ((ptw & PostTransportLocate) && !config.get_external_sync() && pending_locate_roll) {
604 request_transport_speed (1.0);
605 pending_locate_roll = false;
610 Session::check_declick_out ()
612 bool locate_required = transport_sub_state & PendingLocate;
614 /* this is called after a process() iteration. if PendingDeclickOut was set,
615 it means that we were waiting to declick the output (which has just been
616 done) before doing something else. this is where we do that "something else".
618 note: called from the audio thread.
621 if (transport_sub_state & PendingDeclickOut) {
623 if (locate_required) {
624 start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
625 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
627 stop_transport (pending_abort);
628 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
634 Session::unset_play_loop ()
637 clear_events (SessionEvent::AutoLoop);
639 // set all tracks to NOT use internal looping
640 boost::shared_ptr<RouteList> rl = routes.reader ();
641 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
642 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
643 if (tr && !tr->hidden()) {
650 Session::set_play_loop (bool yn)
652 /* Called from event-handling context */
656 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
657 /* nothing to do, or can't change loop status while recording */
661 if (yn && Config->get_seamless_loop() && synced_to_jack()) {
662 warning << string_compose (_("Seamless looping cannot be supported while %1 is using JACK transport.\n"
663 "Recommend changing the configured options"), PROGRAM_NAME)
676 if (Config->get_seamless_loop()) {
677 // set all tracks to use internal looping
678 boost::shared_ptr<RouteList> rl = routes.reader ();
679 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
680 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
681 if (tr && !tr->hidden()) {
687 // set all tracks to NOT use internal looping
688 boost::shared_ptr<RouteList> rl = routes.reader ();
689 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
690 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
691 if (tr && !tr->hidden()) {
697 /* put the loop event into the event list */
699 SessionEvent* event = new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f);
702 /* locate to start of loop and roll. If doing seamless loop, force a
703 locate+buffer refill even if we are positioned there already.
706 start_locate (loc->start(), true, true, false, Config->get_seamless_loop());
714 TransportStateChange ();
717 Session::flush_all_inserts ()
719 boost::shared_ptr<RouteList> r = routes.reader ();
721 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
722 (*i)->flush_processors ();
727 Session::start_locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
729 if (synced_to_jack()) {
734 _slave->speed_and_position (sp, pos);
736 if (target_frame != pos) {
738 /* tell JACK to change transport position, and we will
739 follow along later in ::follow_slave()
742 _engine.transport_locate (target_frame);
744 if (sp != 1.0f && with_roll) {
745 _engine.transport_start ();
751 locate (target_frame, with_roll, with_flush, with_loop, force);
756 Session::micro_locate (nframes_t distance)
758 boost::shared_ptr<RouteList> rl = routes.reader();
759 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
760 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
761 if (tr && !tr->can_internal_playback_seek (distance)) {
766 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
767 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
769 tr->internal_playback_seek (distance);
773 _transport_frame += distance;
777 /** @param with_mmc true to send a MMC locate command when the locate is done */
779 Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force, bool with_mmc)
781 if (actively_recording() && !with_loop) {
785 if (!force && _transport_frame == target_frame && !loop_changing && !with_loop) {
787 set_transport_speed (1.0, false);
789 loop_changing = false;
790 Located (); /* EMIT SIGNAL */
794 // Update Timecode time
795 // [DR] FIXME: find out exactly where this should go below
796 _transport_frame = target_frame;
797 timecode_time(_transport_frame, transmitting_timecode_time);
798 outbound_mtc_timecode_frame = _transport_frame;
799 next_quarter_frame_to_send = 0;
801 if (_transport_speed && (!with_loop || loop_changing)) {
802 /* schedule a declick. we'll be called again when its done */
804 if (!(transport_sub_state & PendingDeclickOut)) {
805 transport_sub_state |= (PendingDeclickOut|PendingLocate);
806 pending_locate_frame = target_frame;
807 pending_locate_roll = with_roll;
808 pending_locate_flush = with_flush;
813 if (transport_rolling() && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) {
814 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
817 if (force || !with_loop || loop_changing) {
819 PostTransportWork todo = PostTransportLocate;
822 todo = PostTransportWork (todo | PostTransportRoll);
825 add_post_transport_work (todo);
826 _butler->schedule_transport_work ();
830 /* this is functionally what clear_clicks() does but with a tentative lock */
832 Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
834 if (clickm.locked()) {
836 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
845 /* switch from input if we're going to roll */
846 if (Config->get_monitoring_model() == HardwareMonitoring) {
848 boost::shared_ptr<RouteList> rl = routes.reader();
849 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
850 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
851 if (tr && tr->record_enabled ()) {
852 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
853 tr->monitor_input (!config.get_auto_input());
858 /* otherwise we're going to stop, so do the opposite */
859 if (Config->get_monitoring_model() == HardwareMonitoring) {
861 boost::shared_ptr<RouteList> rl = routes.reader();
862 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
863 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
864 if (tr && tr->record_enabled ()) {
865 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
866 tr->monitor_input (true);
872 /* cancel looped playback if transport pos outside of loop range */
874 Location* al = _locations->auto_loop_location();
876 if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
877 // cancel looping directly, this is called from event handling context
878 set_play_loop (false);
880 else if (al && _transport_frame == al->start()) {
882 // this is only necessary for seamless looping
884 boost::shared_ptr<RouteList> rl = routes.reader();
885 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
886 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
887 if (tr && tr->record_enabled ()) {
888 // tell it we've looped, so it can deal with the record state
889 tr->transport_looped(_transport_frame);
894 TransportLooped(); // EMIT SIGNAL
898 loop_changing = false;
900 _send_timecode_update = true;
903 send_mmc_locate (_transport_frame);
906 Located (); /* EMIT SIGNAL */
909 /** Set the transport speed.
910 * @param speed New speed
914 Session::set_transport_speed (double speed, bool abort, bool clear_state)
916 DEBUG_TRACE (DEBUG::Transport, string_compose ("Set transport speed to %1, abort = %2 clear_state = %3, current = %4\n", speed, abort, clear_state, _transport_speed));
918 if (_transport_speed == speed) {
922 _target_transport_speed = fabs(speed);
924 /* 8.0 max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
925 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
929 speed = min (8.0, speed);
930 } else if (speed < 0) {
931 speed = max (-8.0, speed);
934 if (transport_rolling() && speed == 0.0) {
936 /* we are rolling and we want to stop */
938 if (Config->get_monitoring_model() == HardwareMonitoring)
940 boost::shared_ptr<RouteList> rl = routes.reader();
941 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
942 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
943 if (tr && tr->record_enabled ()) {
944 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
945 tr->monitor_input (true);
950 if (synced_to_jack ()) {
952 /* do this here because our response to the slave won't
958 _engine.transport_stop ();
960 stop_transport (abort);
963 } else if (transport_stopped() && speed == 1.0) {
965 /* we are stopped and we want to start rolling at speed 1 */
967 if (Config->get_monitoring_model() == HardwareMonitoring) {
969 boost::shared_ptr<RouteList> rl = routes.reader();
970 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
971 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
972 if (config.get_auto_input() && tr && tr->record_enabled ()) {
973 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
974 tr->monitor_input (false);
979 if (synced_to_jack()) {
980 _engine.transport_start ();
987 if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
988 warning << string_compose (_("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
994 if (actively_recording()) {
998 if (speed > 0.0 && _transport_frame == current_end_frame()) {
1002 if (speed < 0.0 && _transport_frame == 0) {
1008 /* if we are reversing relative to the current speed, or relative to the speed
1009 before the last stop, then we have to do extra work.
1012 PostTransportWork todo = PostTransportWork (0);
1014 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
1015 todo = PostTransportWork (todo | PostTransportReverse);
1016 _last_roll_or_reversal_location = _transport_frame;
1019 _last_transport_speed = _transport_speed;
1020 _transport_speed = speed;
1022 boost::shared_ptr<RouteList> rl = routes.reader();
1023 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1024 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1025 if (tr && tr->realtime_set_speed (tr->speed(), true)) {
1026 todo = PostTransportWork (todo | PostTransportSpeed);
1032 add_post_transport_work (todo);
1033 _butler->schedule_transport_work ();
1039 /** Stop the transport. */
1041 Session::stop_transport (bool abort, bool clear_state)
1043 if (_transport_speed == 0.0f) {
1047 if (actively_recording() && !(transport_sub_state & StopPendingCapture) && _worst_output_latency > current_block_size) {
1049 boost::shared_ptr<RouteList> rl = routes.reader();
1050 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1051 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1053 tr->prepare_to_stop (_transport_frame);
1057 /* we need to capture the audio that has still not yet been received by the system
1058 at the time the stop is requested, so we have to roll past that time.
1060 we want to declick before stopping, so schedule the autostop for one
1061 block before the actual end. we'll declick in the subsequent block,
1062 and then we'll really be stopped.
1065 SessionEvent *ev = new SessionEvent (SessionEvent::StopOnce, SessionEvent::Replace,
1066 _transport_frame + _worst_output_latency - current_block_size,
1070 transport_sub_state |= StopPendingCapture;
1071 pending_abort = abort;
1076 if ((transport_sub_state & PendingDeclickOut) == 0) {
1078 if (!(transport_sub_state & StopPendingCapture)) {
1079 boost::shared_ptr<RouteList> rl = routes.reader();
1080 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1081 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1083 tr->prepare_to_stop (_transport_frame);
1088 transport_sub_state |= PendingDeclickOut;
1089 /* we'll be called again after the declick */
1090 pending_abort = abort;
1094 realtime_stop (abort, clear_state);
1095 _butler->schedule_transport_work ();
1099 Session::start_transport ()
1101 _last_roll_location = _transport_frame;
1102 _last_roll_or_reversal_location = _transport_frame;
1104 have_looped = false;
1106 /* if record status is Enabled, move it to Recording. if its
1107 already Recording, move it to Disabled.
1110 switch (record_status()) {
1112 if (!config.get_punch_in()) {
1119 disable_record (false);
1127 transport_sub_state |= PendingDeclickIn;
1129 _transport_speed = 1.0;
1130 _target_transport_speed = 1.0;
1132 boost::shared_ptr<RouteList> rl = routes.reader();
1133 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1134 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1136 tr->realtime_set_speed (tr->speed(), true);
1138 (*i)->automation_snapshot (_transport_frame, true);
1141 Timecode::Time time;
1142 timecode_time_subframes (_transport_frame, time);
1143 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
1145 TransportStateChange (); /* EMIT SIGNAL */
1148 /** Do any transport work in the audio thread that needs to be done after the
1149 * transport thread is finished. Audio thread, realtime safe.
1152 Session::post_transport ()
1154 PostTransportWork ptw = post_transport_work ();
1156 if (ptw & PostTransportAudition) {
1157 if (auditioner && auditioner->auditioning()) {
1158 process_function = &Session::process_audition;
1160 process_function = &Session::process_with_events;
1164 if (ptw & PostTransportStop) {
1166 transport_sub_state = 0;
1169 if (ptw & PostTransportLocate) {
1171 if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
1175 transport_sub_state = 0;
1180 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
1183 set_post_transport_work (PostTransportWork (0));
1187 Session::reset_rf_scale (nframes_t motion)
1189 cumulative_rf_motion += motion;
1191 if (cumulative_rf_motion < 4 * _current_frame_rate) {
1193 } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
1195 } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
1207 Session::use_sync_source (Slave* new_slave)
1209 /* Runs in process() context */
1211 bool non_rt_required = false;
1213 /* XXX this deletion is problematic because we're in RT context */
1218 boost::shared_ptr<RouteList> rl = routes.reader();
1219 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1220 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1221 if (tr && !tr->hidden()) {
1222 if (tr->realtime_set_speed (tr->speed(), true)) {
1223 non_rt_required = true;
1225 tr->set_slaved (_slave != 0);
1229 if (non_rt_required) {
1230 add_post_transport_work (PostTransportSpeed);
1231 _butler->schedule_transport_work ();
1238 Session::drop_sync_source ()
1240 request_sync_source (0);
1244 Session::switch_to_sync_source (SyncSource src)
1248 DEBUG_TRACE (DEBUG::Slave, string_compose ("Setting up sync source %1\n", enum_2_string (src)));
1252 if (_slave && dynamic_cast<MTC_Slave*>(_slave)) {
1257 new_slave = new MTC_Slave (*this, *MIDI::Manager::instance()->mtc_input_port());
1260 catch (failed_constructor& err) {
1266 if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
1271 new_slave = new MIDIClock_Slave (*this, *MIDI::Manager::instance()->midi_clock_input_port(), 24);
1274 catch (failed_constructor& err) {
1280 if (_slave && dynamic_cast<JACK_Slave*>(_slave)) {
1284 new_slave = new JACK_Slave (_engine.jack());
1292 request_sync_source (new_slave);
1296 Session::reverse_track_buffers ()
1298 add_post_transport_work (PostTransportReverse);
1299 _butler->schedule_transport_work ();
1303 Session::set_track_speed (Track* track, double speed)
1305 if (track->realtime_set_speed (speed, false)) {
1306 add_post_transport_work (PostTransportSpeed);
1307 _butler->schedule_transport_work ();
1313 Session::unset_play_range ()
1315 _play_range = false;
1316 _clear_event_type (SessionEvent::RangeStop);
1317 _clear_event_type (SessionEvent::RangeLocate);
1321 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1325 /* Called from event-processing context */
1327 unset_play_range ();
1329 if (range.empty()) {
1330 /* _play_range set to false in unset_play_range()
1332 if (!leave_rolling) {
1333 /* stop transport */
1334 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1342 /* cancel loop play */
1345 list<AudioRange>::size_type sz = range.size();
1349 list<AudioRange>::iterator i = range.begin();
1350 list<AudioRange>::iterator next;
1352 while (i != range.end()) {
1357 /* locating/stopping is subject to delays for declicking.
1360 nframes_t requested_frame = (*i).end;
1362 if (requested_frame > current_block_size) {
1363 requested_frame -= current_block_size;
1365 requested_frame = 0;
1368 if (next == range.end()) {
1369 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_frame, 0, 0.0f);
1371 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_frame, (*next).start, 0.0f);
1379 } else if (sz == 1) {
1381 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1386 /* save range so we can do auto-return etc. */
1388 current_audio_range = range;
1390 /* now start rolling at the right place */
1392 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1395 TransportStateChange ();
1399 Session::request_bounded_roll (nframes_t start, nframes_t end)
1401 AudioRange ar (start, end, 0);
1402 list<AudioRange> lar;
1405 request_play_range (&lar, true);
1408 Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
1410 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1411 ev->target2_frame = start;
1416 Session::engine_halted ()
1420 /* there will be no more calls to process(), so
1421 we'd better clean up for ourselves, right now.
1423 but first, make sure the butler is out of
1427 g_atomic_int_set (&_butler->should_do_transport_work, 0);
1428 set_post_transport_work (PostTransportWork (0));
1431 realtime_stop (false, true);
1432 non_realtime_stop (false, 0, ignored);
1433 transport_sub_state = 0;
1435 TransportStateChange (); /* EMIT SIGNAL */
1440 Session::xrun_recovery ()
1442 // can't cast away volatile so copy and emit that
1443 nframes64_t tframe = _transport_frame;
1444 Xrun (tframe); //EMIT SIGNAL
1446 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1448 /* it didn't actually halt, but we need
1449 to handle things in the same way.
1457 Session::route_processors_changed (RouteProcessorChange c)
1459 if (c.type == RouteProcessorChange::MeterPointChange) {
1463 update_latency_compensation (false, false);
1468 Session::update_latency_compensation (bool with_stop, bool abort)
1470 bool update_jack = false;
1471 PostTransportWork ptw;
1473 if (_state_of_the_state & Deletion) {
1477 _worst_track_latency = 0;
1478 ptw = post_transport_work();
1480 #undef DEBUG_LATENCY
1481 #ifdef DEBUG_LATENCY
1482 cerr << "\n---------------------------------\nUPDATE LATENCY\n";
1485 boost::shared_ptr<RouteList> r = routes.reader ();
1487 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1490 (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
1493 nframes_t old_latency = (*i)->output()->signal_latency ();
1494 nframes_t track_latency = (*i)->update_total_latency ();
1496 if (old_latency != track_latency) {
1497 (*i)->input()->update_port_total_latencies ();
1498 (*i)->output()->update_port_total_latencies ();
1502 if (!(*i)->is_hidden() && ((*i)->active())) {
1503 _worst_track_latency = max (_worst_track_latency, track_latency);
1508 _engine.update_total_latencies ();
1511 #ifdef DEBUG_LATENCY
1512 cerr << "\tworst was " << _worst_track_latency << endl;
1515 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1516 (*i)->set_latency_delay (_worst_track_latency);
1519 set_worst_io_latencies ();
1521 /* reflect any changes in latencies into capture offsets
1524 boost::shared_ptr<RouteList> rl = routes.reader();
1525 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1526 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1528 tr->set_capture_offset ();
1534 Session::allow_auto_play (bool yn)
1536 auto_play_legal = yn;
1540 Session::reset_jack_connection (jack_client_t* jack)
1544 if (_slave && ((js = dynamic_cast<JACK_Slave*> (_slave)) != 0)) {
1545 js->reset_client (jack);
1550 Session::maybe_stop (nframes_t limit)
1552 if ((_transport_speed > 0.0f && _transport_frame >= limit) || (_transport_speed < 0.0f && _transport_frame == 0)) {
1553 if (synced_to_jack () && config.get_jack_time_master ()) {
1554 _engine.transport_stop ();
1555 } else if (!synced_to_jack ()) {
1564 Session::send_mmc_locate (nframes64_t t)
1566 Timecode::Time time;
1567 timecode_time_subframes (t, time);
1568 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (time));
1571 /** Ask the transport to not send timecode until further notice. The suspension
1572 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1573 * should be checked by the caller to find out when.
1576 Session::request_suspend_timecode_transmission ()
1578 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1583 Session::request_resume_timecode_transmission ()
1585 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1590 Session::timecode_transmission_suspended () const
1592 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;