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.
25 #include <sigc++/bind.h>
26 #include <sigc++/retype.h>
29 #include <pbd/error.h>
30 #include <glibmm/thread.h>
31 #include <pbd/pthread_utils.h>
33 #include <midi++/mmc.h>
34 #include <midi++/port.h>
36 #include <ardour/ardour.h>
37 #include <ardour/audioengine.h>
38 #include <ardour/session.h>
39 #include <ardour/audio_diskstream.h>
40 #include <ardour/auditioner.h>
41 #include <ardour/slave.h>
42 #include <ardour/location.h>
47 using namespace ARDOUR;
52 Session::request_input_change_handling ()
54 Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
59 Session::request_slave_source (SlaveSource src, jack_nframes_t pos)
61 Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, pos, 0.0);
63 if (src == Session::JACK) {
64 /* could set_seamless_loop() be disposed of entirely?*/
65 set_seamless_loop (false);
68 set_seamless_loop (true);
75 Session::request_transport_speed (float speed)
77 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
82 Session::request_diskstream_speed (Diskstream& ds, float speed)
84 Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
90 Session::request_stop (bool abort)
92 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort);
97 Session::request_locate (jack_nframes_t target_frame, bool with_roll)
99 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, false);
104 Session::force_locate (jack_nframes_t target_frame, bool with_roll)
106 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true);
111 Session::request_auto_loop (bool yn)
114 Location *location = _locations.auto_loop_location();
116 if (location == 0 && yn) {
117 error << _("Cannot loop - no loop range defined")
122 ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
125 if (!yn && seamless_loop && transport_rolling()) {
126 // request an immediate locate to refresh the diskstreams
127 // after disabling looping
128 request_locate (_transport_frame-1, true);
133 Session::set_seamless_loop (bool yn)
135 if (seamless_loop != yn) {
138 if (auto_loop && transport_rolling()) {
139 // to reset diskstreams etc
140 request_auto_loop (true);
143 ControlChanged (SeamlessLoop); /* EMIT */
148 Session::realtime_stop (bool abort)
150 /* assume that when we start, we'll be moving forwards */
152 if (_transport_speed < 0.0f) {
153 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse);
155 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop);
158 if (actively_recording()) {
160 /* move the transport position back to where the
161 request for a stop was noticed. we rolled
162 past that point to pick up delayed input.
165 #ifndef LEAVE_TRANSPORT_UNADJUSTED
166 decrement_transport_position (_worst_output_latency);
169 /* the duration change is not guaranteed to have happened, but is likely */
171 post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
175 post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
178 _clear_event_type (Event::StopOnce);
179 _clear_event_type (Event::RangeStop);
180 _clear_event_type (Event::RangeLocate);
182 disable_record (true);
184 reset_slave_state ();
186 _transport_speed = 0;
188 transport_sub_state = (auto_return ? AutoReturning : 0);
192 Session::butler_transport_work ()
194 Glib::RWLock::ReaderLock dsm (diskstream_lock);
195 boost::shared_ptr<RouteList> r = routes.reader ();
197 if (post_transport_work & PostTransportCurveRealloc) {
198 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
199 (*i)->curve_reallocate();
203 if (post_transport_work & PostTransportInputChange) {
204 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
205 (*i)->non_realtime_input_change ();
209 if (post_transport_work & PostTransportSpeed) {
210 non_realtime_set_speed ();
213 if (post_transport_work & PostTransportReverse) {
217 cumulative_rf_motion = 0;
220 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
221 if (!(*i)->hidden()) {
222 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
223 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
226 (*i)->seek (_transport_frame);
232 if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
233 non_realtime_stop (post_transport_work & PostTransportAbort);
236 if (post_transport_work & PostTransportOverWrite) {
237 non_realtime_overwrite ();
240 if (post_transport_work & PostTransportAudition) {
241 non_realtime_set_audition ();
244 g_atomic_int_dec_and_test (&butler_should_do_transport_work);
248 Session::non_realtime_set_speed ()
250 Glib::RWLock::ReaderLock lm (diskstream_lock);
252 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
253 (*i)->non_realtime_set_speed ();
258 Session::non_realtime_overwrite ()
260 Glib::RWLock::ReaderLock lm (diskstream_lock);
262 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
263 if ((*i)->pending_overwrite) {
264 (*i)->overwrite_existing_buffers ();
270 Session::non_realtime_stop (bool abort)
278 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
279 if ((*i)->get_captured_frames () != 0) {
285 /* stop and locate are merged here because they share a lot of common stuff */
288 now = localtime (&xnow);
291 auditioner->cancel_audition ();
295 cumulative_rf_motion = 0;
299 begin_reversible_command ("capture");
301 Location* loc = _locations.end_location();
302 bool change_end = false;
304 if (_transport_frame < loc->end()) {
306 /* stopped recording before current end */
308 if (_end_location_is_free) {
310 /* first capture for this session, move end back to where we are */
315 } else if (_transport_frame > loc->end()) {
317 /* stopped recording after the current end, extend it */
323 add_undo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end())));
324 add_redo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame)));
327 _end_location_is_free = false;
328 _have_captured = true;
331 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
332 (*i)->transport_stopped (*now, xnow, abort);
335 boost::shared_ptr<RouteList> r = routes.reader ();
337 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
338 if (!(*i)->hidden()) {
339 (*i)->set_pending_declick (0);
344 commit_reversible_command ();
347 if (_engine.running()) {
348 update_latency_compensation (true, abort);
351 if (auto_return || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
353 if (pending_locate_flush) {
354 flush_all_redirects ();
357 if ((auto_return || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
359 _transport_frame = last_stop_frame;
361 if (synced_to_jack()) {
362 _engine.transport_locate (_transport_frame);
366 #ifndef LEAVE_TRANSPORT_UNADJUSTED
370 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
371 if (!(*i)->hidden()) {
372 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
373 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
376 (*i)->seek (_transport_frame);
381 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
383 #ifdef LEAVE_TRANSPORT_UNADJUSTED
387 last_stop_frame = _transport_frame;
389 send_full_time_code ();
390 deliver_mmc (MIDI::MachineControl::cmdStop, 0);
391 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
395 /* XXX its a little odd that we're doing this here
396 when realtime_stop(), which has already executed,
400 if (!Config->get_latched_record_enable()) {
401 g_atomic_int_set (&_record_status, Disabled);
403 g_atomic_int_set (&_record_status, Enabled);
405 RecordStateChanged (); /* emit signal */
408 if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
409 /* capture start has been changed, so save pending state */
410 save_state ("", true);
413 /* always try to get rid of this */
415 remove_pending_capture_state ();
417 /* save the current state of things if appropriate */
420 save_state (_current_snapshot_name);
423 if (post_transport_work & PostTransportDuration) {
424 DurationChanged (); /* EMIT SIGNAL */
427 if (post_transport_work & PostTransportStop) {
430 /* do not turn off autoloop on stop */
434 PositionChanged (_transport_frame); /* EMIT SIGNAL */
435 TransportStateChange (); /* EMIT SIGNAL */
437 /* and start it up again if relevant */
439 if ((post_transport_work & PostTransportLocate) && _slave_type == None && pending_locate_roll) {
440 request_transport_speed (1.0);
441 pending_locate_roll = false;
446 Session::check_declick_out ()
448 bool locate_required = transport_sub_state & PendingLocate;
450 /* this is called after a process() iteration. if PendingDeclickOut was set,
451 it means that we were waiting to declick the output (which has just been
452 done) before doing something else. this is where we do that "something else".
454 note: called from the audio thread.
457 if (transport_sub_state & PendingDeclickOut) {
459 if (locate_required) {
460 start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
461 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
463 stop_transport (pending_abort);
464 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
470 Session::set_auto_loop (bool yn)
472 /* Called from event-handling context */
474 if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
480 if (yn && seamless_loop && synced_to_jack()) {
481 warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
482 "Recommend changing the configured options")
488 if ((auto_loop = yn)) {
493 if ((loc = _locations.auto_loop_location()) != 0) {
496 // set all diskstreams to use internal looping
497 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
498 if (!(*i)->hidden()) {
499 (*i)->set_loop (loc);
504 // set all diskstreams to NOT use internal looping
505 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
506 if (!(*i)->hidden()) {
512 /* stick in the loop event */
514 Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
517 /* locate to start of loop and roll if current pos is outside of the loop range */
518 if (_transport_frame < loc->start() || _transport_frame > loc->end()) {
519 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
523 // locate to current position (+ 1 to force reload)
524 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, _transport_frame + 1, 0, !synced_to_jack());
532 clear_events (Event::AutoLoop);
534 // set all diskstreams to NOT use internal looping
535 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
536 if (!(*i)->hidden()) {
543 ControlChanged (AutoLoop); /* EMIT SIGNAL */
547 Session::flush_all_redirects ()
549 boost::shared_ptr<RouteList> r = routes.reader ();
551 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
552 (*i)->flush_redirects ();
557 Session::start_locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
559 if (synced_to_jack()) {
564 _slave->speed_and_position (sp, pos);
566 if (target_frame != pos) {
568 /* tell JACK to change transport position, and we will
569 follow along later in ::follow_slave()
572 _engine.transport_locate (target_frame);
574 if (sp != 1.0f && with_roll) {
575 _engine.transport_start ();
582 locate (target_frame, with_roll, with_flush, with_loop);
587 Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
589 if (actively_recording()) {
593 if (_transport_frame == target_frame && !loop_changing && !with_loop) {
595 set_transport_speed (1.0, false);
597 loop_changing = false;
601 _transport_frame = target_frame;
603 if (_transport_speed && (!with_loop || loop_changing)) {
604 /* schedule a declick. we'll be called again when its done */
606 if (!(transport_sub_state & PendingDeclickOut)) {
607 transport_sub_state |= (PendingDeclickOut|PendingLocate);
608 pending_locate_frame = target_frame;
609 pending_locate_roll = with_roll;
610 pending_locate_flush = with_flush;
615 if (transport_rolling() && !auto_play && !with_roll && !(synced_to_jack() && auto_loop)) {
616 realtime_stop (false);
619 if ( !with_loop || loop_changing) {
621 post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
624 post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll);
627 schedule_butler_transport_work ();
631 /* this is functionally what clear_clicks() does but with a tentative lock */
633 Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
635 if (clickm.locked()) {
637 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
646 /* switch from input if we're going to roll */
647 if (Config->get_use_hardware_monitoring()) {
648 /* Even though this is called from RT context we are using
649 a non-tentative rwlock here, because the action must occur.
650 The rarity and short potential lock duration makes this "OK"
652 Glib::RWLock::ReaderLock dsm (diskstream_lock);
653 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
654 if ((*i)->record_enabled ()) {
655 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
656 (*i)->monitor_input (!auto_input);
661 /* otherwise we're going to stop, so do the opposite */
662 if (Config->get_use_hardware_monitoring()) {
663 /* Even though this is called from RT context we are using
664 a non-tentative rwlock here, because the action must occur.
665 The rarity and short potential lock duration makes this "OK"
667 Glib::RWLock::ReaderLock dsm (diskstream_lock);
668 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
669 if ((*i)->record_enabled ()) {
670 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
671 (*i)->monitor_input (true);
677 /* cancel autoloop if transport pos outside of loop range */
679 Location* al = _locations.auto_loop_location();
681 if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
682 // cancel looping directly, this is called from event handling context
683 set_auto_loop(false);
687 loop_changing = false;
691 Session::set_transport_speed (float speed, bool abort)
693 if (_transport_speed == speed) {
698 speed = min (8.0f, speed);
699 } else if (speed < 0) {
700 speed = max (-8.0f, speed);
703 if (transport_rolling() && speed == 0.0) {
705 if (Config->get_use_hardware_monitoring())
707 /* Even though this is called from RT context we are using
708 a non-tentative rwlock here, because the action must occur.
709 The rarity and short potential lock duration makes this "OK"
711 Glib::RWLock::ReaderLock dsm (diskstream_lock);
712 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
713 if ((*i)->record_enabled ()) {
714 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
715 (*i)->monitor_input (true);
720 if (synced_to_jack ()) {
721 _engine.transport_stop ();
723 stop_transport (abort);
726 } else if (transport_stopped() && speed == 1.0) {
728 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
732 if (Config->get_use_hardware_monitoring()) {
733 /* Even though this is called from RT context we are using
734 a non-tentative rwlock here, because the action must occur.
735 The rarity and short potential lock duration makes this "OK"
737 Glib::RWLock::ReaderLock dsm (diskstream_lock);
738 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
739 if (auto_input && (*i)->record_enabled ()) {
740 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
741 (*i)->monitor_input (false);
746 if (synced_to_jack()) {
747 _engine.transport_start ();
754 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
758 if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
759 warning << _("Global varispeed cannot be supported while Ardour is connected to JACK transport control")
764 if (actively_recording()) {
768 if (speed > 0.0f && _transport_frame == current_end_frame()) {
772 if (speed < 0.0f && _transport_frame == 0) {
778 /* if we are reversing relative to the current speed, or relative to the speed
779 before the last stop, then we have to do extra work.
782 if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f)) {
783 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
786 _last_transport_speed = _transport_speed;
787 _transport_speed = speed;
789 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
790 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
791 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
795 if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) {
796 schedule_butler_transport_work ();
802 Session::stop_transport (bool abort)
804 if (_transport_speed == 0.0f) {
808 if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
809 _worst_output_latency > current_block_size)
812 /* we need to capture the audio that has still not yet been received by the system
813 at the time the stop is requested, so we have to roll past that time.
815 we want to declick before stopping, so schedule the autostop for one
816 block before the actual end. we'll declick in the subsequent block,
817 and then we'll really be stopped.
820 Event *ev = new Event (Event::StopOnce, Event::Replace,
821 _transport_frame + _worst_output_latency - current_block_size,
825 transport_sub_state |= StopPendingCapture;
826 pending_abort = abort;
830 if ((transport_sub_state & PendingDeclickOut) == 0) {
831 transport_sub_state |= PendingDeclickOut;
832 /* we'll be called again after the declick */
836 realtime_stop (abort);
837 schedule_butler_transport_work ();
841 Session::start_transport ()
843 _last_roll_location = _transport_frame;
845 /* if record status is Enabled, move it to Recording. if its
846 already Recording, move it to Disabled.
849 switch (record_status()) {
857 disable_record (false);
864 if (!synced_to_jack() || _exporting) {
865 actually_start_transport ();
867 waiting_to_start = true;
872 Session::actually_start_transport ()
874 waiting_to_start = false;
876 transport_sub_state |= PendingDeclickIn;
877 _transport_speed = 1.0;
879 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
880 (*i)->realtime_set_speed ((*i)->speed(), true);
883 send_mmc_in_another_thread (MIDI::MachineControl::cmdDeferredPlay, 0);
885 TransportStateChange (); /* EMIT SIGNAL */
889 Session::post_transport ()
891 if (post_transport_work & PostTransportAudition) {
892 if (auditioner && auditioner->active()) {
893 process_function = &Session::process_audition;
895 process_function = &Session::process_with_events;
899 if (post_transport_work & PostTransportStop) {
901 transport_sub_state = 0;
904 if (post_transport_work & PostTransportLocate) {
906 if ((auto_play && !_exporting) || (post_transport_work & PostTransportRoll)) {
911 transport_sub_state = 0;
917 post_transport_work = PostTransportWork (0);
921 Session::set_rf_speed (float speed)
924 cumulative_rf_motion = 0;
929 Session::reset_rf_scale (jack_nframes_t motion)
931 cumulative_rf_motion += motion;
933 if (cumulative_rf_motion < 4 * _current_frame_rate) {
935 } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
937 } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
949 Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
951 bool reverse = false;
952 bool non_rt_required = false;
954 if (src == _slave_type) {
958 if (_transport_speed) {
959 error << _("please stop the transport before adjusting slave settings") << endmsg;
960 /* help out non-MVC friendly UI's by telling them the slave type changed */
961 ControlChanged (SlaveType); /* EMIT SIGNAL */
965 // if (src == JACK && Config->get_jack_time_master()) {
975 if (_transport_speed < 0.0) {
987 _slave = new MTC_Slave (*this, *_mtc_port);
990 catch (failed_constructor& err) {
995 error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
998 _desired_transport_speed = _transport_speed;
1002 _slave = new JACK_Slave (_engine.jack());
1003 _desired_transport_speed = _transport_speed;
1009 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1010 if (!(*i)->hidden()) {
1011 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
1012 non_rt_required = true;
1014 (*i)->set_slaved (_slave);
1019 reverse_diskstream_buffers ();
1022 if (non_rt_required) {
1023 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1024 schedule_butler_transport_work ();
1028 ControlChanged (SlaveType); /* EMIT SIGNAL */
1034 Session::reverse_diskstream_buffers ()
1036 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
1037 schedule_butler_transport_work ();
1041 Session::set_diskstream_speed (Diskstream* stream, float speed)
1043 if (stream->realtime_set_speed (speed, false)) {
1044 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1045 schedule_butler_transport_work ();
1051 Session::set_audio_range (list<AudioRange>& range)
1053 Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f);
1054 ev->audio_range = range;
1059 Session::request_play_range (bool yn)
1061 Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, 0.0f, yn);
1066 Session::set_play_range (bool yn)
1068 /* Called from event-processing context */
1070 if (_play_range != yn) {
1075 /* stop transport */
1076 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
1080 ControlChanged (PlayRange); /* EMIT SIGNAL */
1085 Session::setup_auto_play ()
1087 /* Called from event-processing context */
1091 _clear_event_type (Event::RangeStop);
1092 _clear_event_type (Event::RangeLocate);
1098 list<AudioRange>::size_type sz = current_audio_range.size();
1102 list<AudioRange>::iterator i = current_audio_range.begin();
1103 list<AudioRange>::iterator next;
1105 while (i != current_audio_range.end()) {
1110 /* locating/stopping is subject to delays for declicking.
1113 jack_nframes_t requested_frame = (*i).end;
1115 if (requested_frame > current_block_size) {
1116 requested_frame -= current_block_size;
1118 requested_frame = 0;
1121 if (next == current_audio_range.end()) {
1122 ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
1124 ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
1132 } else if (sz == 1) {
1134 ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
1139 /* now start rolling at the right place */
1141 ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false);
1146 Session::request_bounded_roll (jack_nframes_t start, jack_nframes_t end)
1149 Event *ev = new Event (Event::StopOnce, Event::Replace, Event::Immediate, end, 0.0);
1151 request_locate (start, true);
1155 Session::engine_halted ()
1157 /* there will be no more calls to process(), so
1158 we'd better clean up for ourselves, right now.
1160 but first, make sure the butler is out of
1164 g_atomic_int_set (&butler_should_do_transport_work, 0);
1165 post_transport_work = PostTransportWork (0);
1168 realtime_stop (false);
1169 non_realtime_stop (false);
1170 transport_sub_state = 0;
1172 TransportStateChange (); /* EMIT SIGNAL */
1177 Session::xrun_recovery ()
1179 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1181 HaltOnXrun (); /* EMIT SIGNAL */
1183 /* it didn't actually halt, but we need
1184 to handle things in the same way.
1192 Session::update_latency_compensation (bool with_stop, bool abort)
1194 bool update_jack = false;
1196 if (_state_of_the_state & Deletion) {
1200 Glib::RWLock::ReaderLock lm2 (diskstream_lock);
1201 _worst_track_latency = 0;
1203 boost::shared_ptr<RouteList> r = routes.reader ();
1205 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1207 (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
1208 (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
1211 jack_nframes_t old_latency = (*i)->signal_latency ();
1212 jack_nframes_t track_latency = (*i)->update_total_latency ();
1214 if (old_latency != track_latency) {
1218 if (!(*i)->hidden() && ((*i)->active())) {
1219 _worst_track_latency = max (_worst_track_latency, track_latency);
1223 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1224 (*i)->set_latency_delay (_worst_track_latency);
1227 /* tell JACK to play catch up */
1230 _engine.update_total_latencies ();
1233 set_worst_io_latencies ();
1235 /* reflect any changes in latencies into capture offsets
1238 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1239 (*i)->set_capture_offset ();
1244 Session::update_latency_compensation_proxy (void* ignored)
1246 update_latency_compensation (false, false);