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>
32 #include <pbd/memento_command.h>
34 #include <midi++/mmc.h>
35 #include <midi++/port.h>
37 #include <ardour/ardour.h>
38 #include <ardour/audioengine.h>
39 #include <ardour/session.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/auditioner.h>
42 #include <ardour/slave.h>
43 #include <ardour/location.h>
48 using namespace ARDOUR;
53 Session::request_input_change_handling ()
55 Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
60 Session::request_slave_source (SlaveSource src, jack_nframes_t pos)
62 Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, pos, 0.0);
64 if (src == Session::JACK) {
65 /* could set_seamless_loop() be disposed of entirely?*/
66 set_seamless_loop (false);
69 set_seamless_loop (true);
76 Session::request_transport_speed (float speed)
78 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
83 Session::request_diskstream_speed (Diskstream& ds, float speed)
85 Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
91 Session::request_stop (bool abort)
93 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort);
98 Session::request_locate (jack_nframes_t target_frame, bool with_roll)
100 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, false);
105 Session::force_locate (jack_nframes_t target_frame, bool with_roll)
107 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true);
112 Session::request_auto_loop (bool yn)
115 Location *location = _locations.auto_loop_location();
117 if (location == 0 && yn) {
118 error << _("Cannot loop - no loop range defined")
123 ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
126 if (!yn && seamless_loop && transport_rolling()) {
127 // request an immediate locate to refresh the diskstreams
128 // after disabling looping
129 request_locate (_transport_frame-1, true);
134 Session::set_seamless_loop (bool yn)
136 if (seamless_loop != yn) {
139 if (auto_loop && transport_rolling()) {
140 // to reset diskstreams etc
141 request_auto_loop (true);
144 ControlChanged (SeamlessLoop); /* EMIT */
149 Session::realtime_stop (bool abort)
151 /* assume that when we start, we'll be moving forwards */
153 if (_transport_speed < 0.0f) {
154 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse);
156 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop);
159 if (actively_recording()) {
161 /* move the transport position back to where the
162 request for a stop was noticed. we rolled
163 past that point to pick up delayed input.
166 #ifndef LEAVE_TRANSPORT_UNADJUSTED
167 decrement_transport_position (_worst_output_latency);
170 /* the duration change is not guaranteed to have happened, but is likely */
172 post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
176 post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
179 _clear_event_type (Event::StopOnce);
180 _clear_event_type (Event::RangeStop);
181 _clear_event_type (Event::RangeLocate);
183 disable_record (true);
185 reset_slave_state ();
187 _transport_speed = 0;
189 transport_sub_state = (auto_return ? AutoReturning : 0);
193 Session::butler_transport_work ()
195 Glib::RWLock::ReaderLock dsm (diskstream_lock);
196 boost::shared_ptr<RouteList> r = routes.reader ();
198 if (post_transport_work & PostTransportCurveRealloc) {
199 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
200 (*i)->curve_reallocate();
204 if (post_transport_work & PostTransportInputChange) {
205 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
206 (*i)->non_realtime_input_change ();
210 if (post_transport_work & PostTransportSpeed) {
211 non_realtime_set_speed ();
214 if (post_transport_work & PostTransportReverse) {
218 cumulative_rf_motion = 0;
221 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
222 if (!(*i)->hidden()) {
223 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
224 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
227 (*i)->seek (_transport_frame);
233 if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
234 non_realtime_stop (post_transport_work & PostTransportAbort);
237 if (post_transport_work & PostTransportOverWrite) {
238 non_realtime_overwrite ();
241 if (post_transport_work & PostTransportAudition) {
242 non_realtime_set_audition ();
245 g_atomic_int_dec_and_test (&butler_should_do_transport_work);
249 Session::non_realtime_set_speed ()
251 Glib::RWLock::ReaderLock lm (diskstream_lock);
253 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
254 (*i)->non_realtime_set_speed ();
259 Session::non_realtime_overwrite ()
261 Glib::RWLock::ReaderLock lm (diskstream_lock);
263 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
264 if ((*i)->pending_overwrite) {
265 (*i)->overwrite_existing_buffers ();
271 Session::non_realtime_stop (bool abort)
279 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
280 if ((*i)->get_captured_frames () != 0) {
286 /* stop and locate are merged here because they share a lot of common stuff */
289 now = localtime (&xnow);
292 auditioner->cancel_audition ();
296 cumulative_rf_motion = 0;
300 begin_reversible_command ("capture");
302 Location* loc = _locations.end_location();
303 bool change_end = false;
305 if (_transport_frame < loc->end()) {
307 /* stopped recording before current end */
309 if (_end_location_is_free) {
311 /* first capture for this session, move end back to where we are */
316 } else if (_transport_frame > loc->end()) {
318 /* stopped recording after the current end, extend it */
324 XMLNode &before = loc->get_state();
325 loc->set_end(_transport_frame);
326 XMLNode &after = loc->get_state();
327 add_command (new MementoCommand<Location>(*loc, &before, &after));
330 _end_location_is_free = false;
331 _have_captured = true;
334 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
335 (*i)->transport_stopped (*now, xnow, abort);
338 boost::shared_ptr<RouteList> r = routes.reader ();
340 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
341 if (!(*i)->hidden()) {
342 (*i)->set_pending_declick (0);
347 commit_reversible_command ();
350 if (_engine.running()) {
351 update_latency_compensation (true, abort);
354 if (auto_return || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
356 if (pending_locate_flush) {
357 flush_all_redirects ();
360 if ((auto_return || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
362 _transport_frame = last_stop_frame;
364 if (synced_to_jack()) {
365 _engine.transport_locate (_transport_frame);
369 #ifndef LEAVE_TRANSPORT_UNADJUSTED
373 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
374 if (!(*i)->hidden()) {
375 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
376 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
379 (*i)->seek (_transport_frame);
384 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
386 #ifdef LEAVE_TRANSPORT_UNADJUSTED
390 last_stop_frame = _transport_frame;
392 send_full_time_code ();
393 deliver_mmc (MIDI::MachineControl::cmdStop, 0);
394 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
398 /* XXX its a little odd that we're doing this here
399 when realtime_stop(), which has already executed,
403 if (!Config->get_latched_record_enable()) {
404 g_atomic_int_set (&_record_status, Disabled);
406 g_atomic_int_set (&_record_status, Enabled);
408 RecordStateChanged (); /* emit signal */
411 if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
412 /* capture start has been changed, so save pending state */
413 save_state ("", true);
417 /* always try to get rid of this */
419 remove_pending_capture_state ();
421 /* save the current state of things if appropriate */
424 save_state (_current_snapshot_name);
425 save_history (_current_snapshot_name);
428 if (post_transport_work & PostTransportDuration) {
429 DurationChanged (); /* EMIT SIGNAL */
432 if (post_transport_work & PostTransportStop) {
435 /* do not turn off autoloop on stop */
439 PositionChanged (_transport_frame); /* EMIT SIGNAL */
440 TransportStateChange (); /* EMIT SIGNAL */
442 /* and start it up again if relevant */
444 if ((post_transport_work & PostTransportLocate) && _slave_type == None && pending_locate_roll) {
445 request_transport_speed (1.0);
446 pending_locate_roll = false;
451 Session::check_declick_out ()
453 bool locate_required = transport_sub_state & PendingLocate;
455 /* this is called after a process() iteration. if PendingDeclickOut was set,
456 it means that we were waiting to declick the output (which has just been
457 done) before doing something else. this is where we do that "something else".
459 note: called from the audio thread.
462 if (transport_sub_state & PendingDeclickOut) {
464 if (locate_required) {
465 start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
466 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
468 stop_transport (pending_abort);
469 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
475 Session::set_auto_loop (bool yn)
477 /* Called from event-handling context */
479 if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
485 if (yn && seamless_loop && synced_to_jack()) {
486 warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
487 "Recommend changing the configured options")
493 if ((auto_loop = yn)) {
498 if ((loc = _locations.auto_loop_location()) != 0) {
501 // set all diskstreams to use internal looping
502 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
503 if (!(*i)->hidden()) {
504 (*i)->set_loop (loc);
509 // set all diskstreams to NOT use internal looping
510 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
511 if (!(*i)->hidden()) {
517 /* stick in the loop event */
519 Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
522 /* locate to start of loop and roll if current pos is outside of the loop range */
523 if (_transport_frame < loc->start() || _transport_frame > loc->end()) {
524 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
528 // locate to current position (+ 1 to force reload)
529 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, _transport_frame + 1, 0, !synced_to_jack());
537 clear_events (Event::AutoLoop);
539 // set all diskstreams to NOT use internal looping
540 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
541 if (!(*i)->hidden()) {
548 ControlChanged (AutoLoop); /* EMIT SIGNAL */
552 Session::flush_all_redirects ()
554 boost::shared_ptr<RouteList> r = routes.reader ();
556 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
557 (*i)->flush_redirects ();
562 Session::start_locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
564 if (synced_to_jack()) {
569 _slave->speed_and_position (sp, pos);
571 if (target_frame != pos) {
573 /* tell JACK to change transport position, and we will
574 follow along later in ::follow_slave()
577 _engine.transport_locate (target_frame);
579 if (sp != 1.0f && with_roll) {
580 _engine.transport_start ();
587 locate (target_frame, with_roll, with_flush, with_loop);
592 Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
594 if (actively_recording()) {
598 if (_transport_frame == target_frame && !loop_changing && !with_loop) {
600 set_transport_speed (1.0, false);
602 loop_changing = false;
606 _transport_frame = target_frame;
608 if (_transport_speed && (!with_loop || loop_changing)) {
609 /* schedule a declick. we'll be called again when its done */
611 if (!(transport_sub_state & PendingDeclickOut)) {
612 transport_sub_state |= (PendingDeclickOut|PendingLocate);
613 pending_locate_frame = target_frame;
614 pending_locate_roll = with_roll;
615 pending_locate_flush = with_flush;
620 if (transport_rolling() && !auto_play && !with_roll && !(synced_to_jack() && auto_loop)) {
621 realtime_stop (false);
624 if ( !with_loop || loop_changing) {
626 post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
629 post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll);
632 schedule_butler_transport_work ();
636 /* this is functionally what clear_clicks() does but with a tentative lock */
638 Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
640 if (clickm.locked()) {
642 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
651 /* switch from input if we're going to roll */
652 if (Config->get_use_hardware_monitoring()) {
653 /* Even though this is called from RT context we are using
654 a non-tentative rwlock here, because the action must occur.
655 The rarity and short potential lock duration makes this "OK"
657 Glib::RWLock::ReaderLock dsm (diskstream_lock);
658 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
659 if ((*i)->record_enabled ()) {
660 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
661 (*i)->monitor_input (!auto_input);
666 /* otherwise we're going to stop, so do the opposite */
667 if (Config->get_use_hardware_monitoring()) {
668 /* Even though this is called from RT context we are using
669 a non-tentative rwlock here, because the action must occur.
670 The rarity and short potential lock duration makes this "OK"
672 Glib::RWLock::ReaderLock dsm (diskstream_lock);
673 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
674 if ((*i)->record_enabled ()) {
675 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
676 (*i)->monitor_input (true);
682 /* cancel autoloop if transport pos outside of loop range */
684 Location* al = _locations.auto_loop_location();
686 if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
687 // cancel looping directly, this is called from event handling context
688 set_auto_loop(false);
692 loop_changing = false;
696 Session::set_transport_speed (float speed, bool abort)
698 if (_transport_speed == speed) {
703 speed = min (8.0f, speed);
704 } else if (speed < 0) {
705 speed = max (-8.0f, speed);
708 if (transport_rolling() && speed == 0.0) {
710 if (Config->get_use_hardware_monitoring())
712 /* Even though this is called from RT context we are using
713 a non-tentative rwlock here, because the action must occur.
714 The rarity and short potential lock duration makes this "OK"
716 Glib::RWLock::ReaderLock dsm (diskstream_lock);
717 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
718 if ((*i)->record_enabled ()) {
719 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
720 (*i)->monitor_input (true);
725 if (synced_to_jack ()) {
726 _engine.transport_stop ();
728 stop_transport (abort);
731 } else if (transport_stopped() && speed == 1.0) {
733 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
737 if (Config->get_use_hardware_monitoring()) {
738 /* Even though this is called from RT context we are using
739 a non-tentative rwlock here, because the action must occur.
740 The rarity and short potential lock duration makes this "OK"
742 Glib::RWLock::ReaderLock dsm (diskstream_lock);
743 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
744 if (auto_input && (*i)->record_enabled ()) {
745 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
746 (*i)->monitor_input (false);
751 if (synced_to_jack()) {
752 _engine.transport_start ();
759 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
763 if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
764 warning << _("Global varispeed cannot be supported while Ardour is connected to JACK transport control")
769 if (actively_recording()) {
773 if (speed > 0.0f && _transport_frame == current_end_frame()) {
777 if (speed < 0.0f && _transport_frame == 0) {
783 /* if we are reversing relative to the current speed, or relative to the speed
784 before the last stop, then we have to do extra work.
787 if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f)) {
788 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
791 _last_transport_speed = _transport_speed;
792 _transport_speed = speed;
794 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
795 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
796 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
800 if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) {
801 schedule_butler_transport_work ();
807 Session::stop_transport (bool abort)
809 if (_transport_speed == 0.0f) {
813 if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
814 _worst_output_latency > current_block_size)
817 /* we need to capture the audio that has still not yet been received by the system
818 at the time the stop is requested, so we have to roll past that time.
820 we want to declick before stopping, so schedule the autostop for one
821 block before the actual end. we'll declick in the subsequent block,
822 and then we'll really be stopped.
825 Event *ev = new Event (Event::StopOnce, Event::Replace,
826 _transport_frame + _worst_output_latency - current_block_size,
830 transport_sub_state |= StopPendingCapture;
831 pending_abort = abort;
835 if ((transport_sub_state & PendingDeclickOut) == 0) {
836 transport_sub_state |= PendingDeclickOut;
837 /* we'll be called again after the declick */
841 realtime_stop (abort);
842 schedule_butler_transport_work ();
846 Session::start_transport ()
848 _last_roll_location = _transport_frame;
850 /* if record status is Enabled, move it to Recording. if its
851 already Recording, move it to Disabled.
854 switch (record_status()) {
862 disable_record (false);
869 if (!synced_to_jack() || _exporting) {
870 actually_start_transport ();
872 waiting_to_start = true;
877 Session::actually_start_transport ()
879 waiting_to_start = false;
881 transport_sub_state |= PendingDeclickIn;
882 _transport_speed = 1.0;
884 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
885 (*i)->realtime_set_speed ((*i)->speed(), true);
888 send_mmc_in_another_thread (MIDI::MachineControl::cmdDeferredPlay, 0);
890 TransportStateChange (); /* EMIT SIGNAL */
894 Session::post_transport ()
896 if (post_transport_work & PostTransportAudition) {
897 if (auditioner && auditioner->active()) {
898 process_function = &Session::process_audition;
900 process_function = &Session::process_with_events;
904 if (post_transport_work & PostTransportStop) {
906 transport_sub_state = 0;
909 if (post_transport_work & PostTransportLocate) {
911 if ((auto_play && !_exporting) || (post_transport_work & PostTransportRoll)) {
916 transport_sub_state = 0;
922 post_transport_work = PostTransportWork (0);
926 Session::set_rf_speed (float speed)
929 cumulative_rf_motion = 0;
934 Session::reset_rf_scale (jack_nframes_t motion)
936 cumulative_rf_motion += motion;
938 if (cumulative_rf_motion < 4 * _current_frame_rate) {
940 } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
942 } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
954 Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
956 bool reverse = false;
957 bool non_rt_required = false;
959 if (src == _slave_type) {
963 if (_transport_speed) {
964 error << _("please stop the transport before adjusting slave settings") << endmsg;
965 /* help out non-MVC friendly UI's by telling them the slave type changed */
966 ControlChanged (SlaveType); /* EMIT SIGNAL */
970 // if (src == JACK && Config->get_jack_time_master()) {
980 if (_transport_speed < 0.0) {
992 _slave = new MTC_Slave (*this, *_mtc_port);
995 catch (failed_constructor& err) {
1000 error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
1003 _desired_transport_speed = _transport_speed;
1007 _slave = new JACK_Slave (_engine.jack());
1008 _desired_transport_speed = _transport_speed;
1014 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1015 if (!(*i)->hidden()) {
1016 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
1017 non_rt_required = true;
1019 (*i)->set_slaved (_slave);
1024 reverse_diskstream_buffers ();
1027 if (non_rt_required) {
1028 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1029 schedule_butler_transport_work ();
1033 ControlChanged (SlaveType); /* EMIT SIGNAL */
1039 Session::reverse_diskstream_buffers ()
1041 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
1042 schedule_butler_transport_work ();
1046 Session::set_diskstream_speed (Diskstream* stream, float speed)
1048 if (stream->realtime_set_speed (speed, false)) {
1049 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1050 schedule_butler_transport_work ();
1056 Session::set_audio_range (list<AudioRange>& range)
1058 Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f);
1059 ev->audio_range = range;
1064 Session::request_play_range (bool yn)
1066 Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, 0.0f, yn);
1071 Session::set_play_range (bool yn)
1073 /* Called from event-processing context */
1075 if (_play_range != yn) {
1080 /* stop transport */
1081 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
1085 ControlChanged (PlayRange); /* EMIT SIGNAL */
1090 Session::setup_auto_play ()
1092 /* Called from event-processing context */
1096 _clear_event_type (Event::RangeStop);
1097 _clear_event_type (Event::RangeLocate);
1103 list<AudioRange>::size_type sz = current_audio_range.size();
1107 list<AudioRange>::iterator i = current_audio_range.begin();
1108 list<AudioRange>::iterator next;
1110 while (i != current_audio_range.end()) {
1115 /* locating/stopping is subject to delays for declicking.
1118 jack_nframes_t requested_frame = (*i).end;
1120 if (requested_frame > current_block_size) {
1121 requested_frame -= current_block_size;
1123 requested_frame = 0;
1126 if (next == current_audio_range.end()) {
1127 ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
1129 ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
1137 } else if (sz == 1) {
1139 ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
1144 /* now start rolling at the right place */
1146 ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false);
1151 Session::request_bounded_roll (jack_nframes_t start, jack_nframes_t end)
1154 Event *ev = new Event (Event::StopOnce, Event::Replace, Event::Immediate, end, 0.0);
1156 request_locate (start, true);
1160 Session::engine_halted ()
1162 /* there will be no more calls to process(), so
1163 we'd better clean up for ourselves, right now.
1165 but first, make sure the butler is out of
1169 g_atomic_int_set (&butler_should_do_transport_work, 0);
1170 post_transport_work = PostTransportWork (0);
1173 realtime_stop (false);
1174 non_realtime_stop (false);
1175 transport_sub_state = 0;
1177 TransportStateChange (); /* EMIT SIGNAL */
1182 Session::xrun_recovery ()
1184 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1186 HaltOnXrun (); /* EMIT SIGNAL */
1188 /* it didn't actually halt, but we need
1189 to handle things in the same way.
1197 Session::update_latency_compensation (bool with_stop, bool abort)
1199 bool update_jack = false;
1201 if (_state_of_the_state & Deletion) {
1205 Glib::RWLock::ReaderLock lm2 (diskstream_lock);
1206 _worst_track_latency = 0;
1208 boost::shared_ptr<RouteList> r = routes.reader ();
1210 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1212 (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
1213 (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
1216 jack_nframes_t old_latency = (*i)->signal_latency ();
1217 jack_nframes_t track_latency = (*i)->update_total_latency ();
1219 if (old_latency != track_latency) {
1223 if (!(*i)->hidden() && ((*i)->active())) {
1224 _worst_track_latency = max (_worst_track_latency, track_latency);
1228 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1229 (*i)->set_latency_delay (_worst_track_latency);
1232 /* tell JACK to play catch up */
1235 _engine.update_total_latencies ();
1238 set_worst_io_latencies ();
1240 /* reflect any changes in latencies into capture offsets
1243 for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1244 (*i)->set_capture_offset ();
1249 Session::update_latency_compensation_proxy (void* ignored)
1251 update_latency_compensation (false, false);