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 <pbd/lockmonitor.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/diskstream.h>
40 #include <ardour/auditioner.h>
41 #include <ardour/slave.h>
42 #include <ardour/location.h>
47 using namespace ARDOUR;
51 Session::request_input_change_handling ()
53 Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
58 Session::request_slave_source (SlaveSource src, jack_nframes_t pos)
60 Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, pos, 0.0);
62 if (src == Session::JACK) {
63 /* could set_seamless_loop() be disposed of entirely?*/
64 set_seamless_loop (false);
67 set_seamless_loop (true);
74 Session::request_transport_speed (float speed)
76 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
81 Session::request_diskstream_speed (DiskStream& ds, float speed)
83 Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
89 Session::request_stop (bool abort)
91 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort);
96 Session::request_locate (jack_nframes_t target_frame, bool with_roll)
98 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, false);
103 Session::force_locate (jack_nframes_t target_frame, bool with_roll)
105 Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true);
110 Session::request_auto_loop (bool yn)
113 Location *location = _locations.auto_loop_location();
115 if (location == 0 && yn) {
116 error << _("Cannot loop - no loop range defined")
121 ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
124 if (!yn && seamless_loop && transport_rolling()) {
125 // request an immediate locate to refresh the diskstreams
126 // after disabling looping
127 request_locate (_transport_frame-1, true);
132 Session::set_seamless_loop (bool yn)
134 if (seamless_loop != yn) {
137 if (auto_loop && transport_rolling()) {
138 // to reset diskstreams etc
139 request_auto_loop (true);
142 ControlChanged (SeamlessLoop); /* EMIT */
147 Session::realtime_stop (bool abort)
149 /* assume that when we start, we'll be moving forwards */
151 if (_transport_speed < 0.0f) {
152 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse);
154 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop);
157 if (actively_recording()) {
159 /* move the transport position back to where the
160 request for a stop was noticed. we rolled
161 past that point to pick up delayed input.
164 #ifndef LEAVE_TRANSPORT_UNADJUSTED
165 decrement_transport_position (_worst_output_latency);
168 /* the duration change is not guaranteed to have happened, but is likely */
170 post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
174 post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
177 _clear_event_type (Event::StopOnce);
178 _clear_event_type (Event::RangeStop);
179 _clear_event_type (Event::RangeLocate);
181 disable_record (true);
183 reset_slave_state ();
185 _transport_speed = 0;
187 transport_sub_state = (auto_return ? AutoReturning : 0);
191 Session::butler_transport_work ()
193 RWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
194 RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
196 if (post_transport_work & PostTransportCurveRealloc) {
197 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
198 (*i)->curve_reallocate();
202 if (post_transport_work & PostTransportInputChange) {
203 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
204 (*i)->non_realtime_input_change ();
208 if (post_transport_work & PostTransportSpeed) {
209 non_realtime_set_speed ();
212 if (post_transport_work & PostTransportReverse) {
216 cumulative_rf_motion = 0;
219 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
220 if (!(*i)->hidden()) {
221 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
222 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
225 (*i)->seek (_transport_frame);
231 if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
232 non_realtime_stop (post_transport_work & PostTransportAbort);
235 if (post_transport_work & PostTransportOverWrite) {
236 non_realtime_overwrite ();
239 if (post_transport_work & PostTransportAudition) {
240 non_realtime_set_audition ();
243 atomic_dec (&butler_should_do_transport_work);
247 Session::non_realtime_set_speed ()
249 RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
251 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
252 (*i)->non_realtime_set_speed ();
257 Session::non_realtime_overwrite ()
259 RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
261 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
262 if ((*i)->pending_overwrite) {
263 (*i)->overwrite_existing_buffers ();
269 Session::non_realtime_stop (bool abort)
277 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
278 if ((*i)->get_captured_frames () != 0) {
284 /* stop and locate are merged here because they share a lot of common stuff */
287 now = localtime (&xnow);
290 auditioner->cancel_audition ();
294 cumulative_rf_motion = 0;
298 begin_reversible_command ("capture");
300 Location* loc = _locations.end_location();
301 bool change_end = false;
303 if (_transport_frame < loc->end()) {
305 /* stopped recording before current end */
307 if (_end_location_is_free) {
309 /* first capture for this session, move end back to where we are */
314 } else if (_transport_frame > loc->end()) {
316 /* stopped recording after the current end, extend it */
322 add_undo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end())));
323 add_redo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame)));
326 _end_location_is_free = false;
327 _have_captured = true;
330 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
331 (*i)->transport_stopped (*now, xnow, abort);
334 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
335 if (!(*i)->hidden()) {
336 (*i)->set_pending_declick (0);
341 commit_reversible_command ();
344 if (_engine.running()) {
345 update_latency_compensation (true, abort);
348 if (auto_return || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
350 if (pending_locate_flush) {
351 flush_all_redirects ();
354 if ((auto_return || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
356 _transport_frame = last_stop_frame;
358 if (synced_to_jack()) {
359 _engine.transport_locate (_transport_frame);
363 #ifndef LEAVE_TRANSPORT_UNADJUSTED
367 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
368 if (!(*i)->hidden()) {
369 if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
370 (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
373 (*i)->seek (_transport_frame);
378 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
380 #ifdef LEAVE_TRANSPORT_UNADJUSTED
384 last_stop_frame = _transport_frame;
386 send_full_time_code ();
387 deliver_mmc (MIDI::MachineControl::cmdStop, 0);
388 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
392 /* XXX its a little odd that we're doing this here
393 when realtime_stop(), which has already executed,
397 if (!Config->get_latched_record_enable()) {
398 atomic_set (&_record_status, Disabled);
400 atomic_set (&_record_status, Enabled);
402 RecordStateChanged (); /* emit signal */
405 if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
406 /* capture start has been changed, so save pending state */
407 save_state ("", true);
410 /* always try to get rid of this */
412 remove_pending_capture_state ();
414 /* save the current state of things if appropriate */
417 save_state (_current_snapshot_name);
420 if (post_transport_work & PostTransportDuration) {
421 DurationChanged (); /* EMIT SIGNAL */
424 if (post_transport_work & PostTransportStop) {
427 /* do not turn off autoloop on stop */
431 PositionChanged (_transport_frame); /* EMIT SIGNAL */
432 TransportStateChange (); /* EMIT SIGNAL */
434 /* and start it up again if relevant */
436 if ((post_transport_work & PostTransportLocate) && _slave_type == None && pending_locate_roll) {
437 request_transport_speed (1.0);
438 pending_locate_roll = false;
443 Session::check_declick_out ()
445 bool locate_required = transport_sub_state & PendingLocate;
447 /* this is called after a process() iteration. if PendingDeclickOut was set,
448 it means that we were waiting to declick the output (which has just been
449 done) before doing something else. this is where we do that "something else".
451 note: called from the audio thread.
454 if (transport_sub_state & PendingDeclickOut) {
456 if (locate_required) {
457 start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
458 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
460 stop_transport (pending_abort);
461 transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
467 Session::set_auto_loop (bool yn)
469 /* Called from event-handling context */
471 if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
477 if (yn && seamless_loop && synced_to_jack()) {
478 warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
479 "Recommend changing the configured options")
485 if ((auto_loop = yn)) {
490 if ((loc = _locations.auto_loop_location()) != 0) {
493 // set all diskstreams to use internal looping
494 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
495 if (!(*i)->hidden()) {
496 (*i)->set_loop (loc);
501 // set all diskstreams to NOT use internal looping
502 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
503 if (!(*i)->hidden()) {
509 /* stick in the loop event */
511 Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
514 /* locate to start of loop and roll if current pos is outside of the loop range */
515 if (_transport_frame < loc->start() || _transport_frame > loc->end()) {
516 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
520 // locate to current position (+ 1 to force reload)
521 event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, _transport_frame + 1, 0, !synced_to_jack());
529 clear_events (Event::AutoLoop);
531 // set all diskstreams to NOT use internal looping
532 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
533 if (!(*i)->hidden()) {
540 ControlChanged (AutoLoop); /* EMIT SIGNAL */
544 Session::flush_all_redirects ()
546 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
547 (*i)->flush_redirects ();
552 Session::start_locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
554 if (synced_to_jack()) {
559 _slave->speed_and_position (sp, pos);
561 if (target_frame != pos) {
563 /* tell JACK to change transport position, and we will
564 follow along later in ::follow_slave()
567 _engine.transport_locate (target_frame);
569 if (sp != 1.0f && with_roll) {
570 _engine.transport_start ();
577 locate (target_frame, with_roll, with_flush, with_loop);
582 Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
584 if (actively_recording()) {
588 if (_transport_frame == target_frame && !loop_changing && !with_loop) {
590 set_transport_speed (1.0, false);
592 loop_changing = false;
596 _transport_frame = target_frame;
598 if (_transport_speed && (!with_loop || loop_changing)) {
599 /* schedule a declick. we'll be called again when its done */
601 if (!(transport_sub_state & PendingDeclickOut)) {
602 transport_sub_state |= (PendingDeclickOut|PendingLocate);
603 pending_locate_frame = target_frame;
604 pending_locate_roll = with_roll;
605 pending_locate_flush = with_flush;
610 if (transport_rolling() && !auto_play && !with_roll && !(synced_to_jack() && auto_loop)) {
611 realtime_stop (false);
614 if ( !with_loop || loop_changing) {
616 post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
619 post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll);
622 schedule_butler_transport_work ();
626 /* this is functionally what clear_clicks() does but with a tentative lock */
628 TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
630 if (clickm.locked()) {
632 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
641 /* switch from input if we're going to roll */
642 if (Config->get_use_hardware_monitoring()) {
643 /* Even though this is called from RT context we are using
644 a non-tentative rwlock here, because the action must occur.
645 The rarity and short potential lock duration makes this "OK"
647 RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
648 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
649 if ((*i)->record_enabled ()) {
650 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
651 (*i)->monitor_input (!auto_input);
656 /* otherwise we're going to stop, so do the opposite */
657 if (Config->get_use_hardware_monitoring()) {
658 /* Even though this is called from RT context we are using
659 a non-tentative rwlock here, because the action must occur.
660 The rarity and short potential lock duration makes this "OK"
662 RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
663 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
664 if ((*i)->record_enabled ()) {
665 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
666 (*i)->monitor_input (true);
672 /* cancel autoloop if transport pos outside of loop range */
674 Location* al = _locations.auto_loop_location();
676 if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
677 // cancel looping directly, this is called from event handling context
678 set_auto_loop(false);
682 loop_changing = false;
686 Session::set_transport_speed (float speed, bool abort)
688 if (_transport_speed == speed) {
693 speed = min (8.0f, speed);
694 } else if (speed < 0) {
695 speed = max (-8.0f, speed);
698 if (transport_rolling() && speed == 0.0) {
700 if (Config->get_use_hardware_monitoring())
702 /* Even though this is called from RT context we are using
703 a non-tentative rwlock here, because the action must occur.
704 The rarity and short potential lock duration makes this "OK"
706 RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
707 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
708 if ((*i)->record_enabled ()) {
709 //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
710 (*i)->monitor_input (true);
715 if (synced_to_jack ()) {
716 _engine.transport_stop ();
718 stop_transport (abort);
721 } else if (transport_stopped() && speed == 1.0) {
723 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
727 if (Config->get_use_hardware_monitoring()) {
728 /* Even though this is called from RT context we are using
729 a non-tentative rwlock here, because the action must occur.
730 The rarity and short potential lock duration makes this "OK"
732 RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
733 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
734 if (auto_input && (*i)->record_enabled ()) {
735 //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
736 (*i)->monitor_input (false);
741 if (synced_to_jack()) {
742 _engine.transport_start ();
749 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
753 if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
754 warning << _("Global varispeed cannot be supported while Ardour is connected to JACK transport control")
759 if (actively_recording()) {
763 if (speed > 0.0f && _transport_frame == current_end_frame()) {
767 if (speed < 0.0f && _transport_frame == 0) {
773 /* if we are reversing relative to the current speed, or relative to the speed
774 before the last stop, then we have to do extra work.
777 if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f)) {
778 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
781 _last_transport_speed = _transport_speed;
782 _transport_speed = speed;
784 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
785 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
786 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
790 if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) {
791 schedule_butler_transport_work ();
797 Session::stop_transport (bool abort)
799 if (_transport_speed == 0.0f) {
803 if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
804 _worst_output_latency > current_block_size)
807 /* we need to capture the audio that has still not yet been received by the system
808 at the time the stop is requested, so we have to roll past that time.
810 we want to declick before stopping, so schedule the autostop for one
811 block before the actual end. we'll declick in the subsequent block,
812 and then we'll really be stopped.
815 Event *ev = new Event (Event::StopOnce, Event::Replace,
816 _transport_frame + _worst_output_latency - current_block_size,
820 transport_sub_state |= StopPendingCapture;
821 pending_abort = abort;
825 if ((transport_sub_state & PendingDeclickOut) == 0) {
826 transport_sub_state |= PendingDeclickOut;
827 /* we'll be called again after the declick */
831 realtime_stop (abort);
832 schedule_butler_transport_work ();
836 Session::start_transport ()
838 _last_roll_location = _transport_frame;
840 /* if record status is Enabled, move it to Recording. if its
841 already Recording, move it to Disabled.
844 switch (record_status()) {
852 disable_record (false);
859 if (!synced_to_jack() || _exporting) {
860 actually_start_transport ();
862 waiting_to_start = true;
867 Session::actually_start_transport ()
869 waiting_to_start = false;
871 transport_sub_state |= PendingDeclickIn;
872 _transport_speed = 1.0;
874 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
875 (*i)->realtime_set_speed ((*i)->speed(), true);
878 send_mmc_in_another_thread (MIDI::MachineControl::cmdDeferredPlay, 0);
880 TransportStateChange (); /* EMIT SIGNAL */
884 Session::post_transport ()
886 if (post_transport_work & PostTransportAudition) {
887 if (auditioner && auditioner->active()) {
888 process_function = &Session::process_audition;
890 process_function = &Session::process_with_events;
894 if (post_transport_work & PostTransportStop) {
896 transport_sub_state = 0;
899 if (post_transport_work & PostTransportLocate) {
901 if ((auto_play && !_exporting) || (post_transport_work & PostTransportRoll)) {
906 transport_sub_state = 0;
912 post_transport_work = PostTransportWork (0);
916 Session::set_rf_speed (float speed)
919 cumulative_rf_motion = 0;
924 Session::reset_rf_scale (jack_nframes_t motion)
926 cumulative_rf_motion += motion;
928 if (cumulative_rf_motion < 4 * _current_frame_rate) {
930 } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
932 } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
944 Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
946 bool reverse = false;
947 bool non_rt_required = false;
949 if (src == _slave_type) {
953 if (_transport_speed) {
954 error << _("please stop the transport before adjusting slave settings") << endmsg;
955 /* help out non-MVC friendly UI's by telling them the slave type changed */
956 ControlChanged (SlaveType); /* EMIT SIGNAL */
960 // if (src == JACK && Config->get_jack_time_master()) {
970 if (_transport_speed < 0.0) {
982 _slave = new MTC_Slave (*this, *_mtc_port);
985 catch (failed_constructor& err) {
990 error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
993 _desired_transport_speed = _transport_speed;
997 _slave = new JACK_Slave (_engine.jack());
998 _desired_transport_speed = _transport_speed;
1004 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1005 if (!(*i)->hidden()) {
1006 if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
1007 non_rt_required = true;
1009 (*i)->set_slaved (_slave);
1014 reverse_diskstream_buffers ();
1017 if (non_rt_required) {
1018 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1019 schedule_butler_transport_work ();
1023 ControlChanged (SlaveType); /* EMIT SIGNAL */
1029 Session::reverse_diskstream_buffers ()
1031 post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
1032 schedule_butler_transport_work ();
1036 Session::set_diskstream_speed (DiskStream* stream, float speed)
1038 if (stream->realtime_set_speed (speed, false)) {
1039 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1040 schedule_butler_transport_work ();
1046 Session::set_audio_range (list<AudioRange>& range)
1048 Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f);
1049 ev->audio_range = range;
1054 Session::request_play_range (bool yn)
1056 Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, 0.0f, yn);
1061 Session::set_play_range (bool yn)
1063 /* Called from event-processing context */
1065 if (_play_range != yn) {
1070 /* stop transport */
1071 Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
1075 ControlChanged (PlayRange); /* EMIT SIGNAL */
1080 Session::setup_auto_play ()
1082 /* Called from event-processing context */
1086 _clear_event_type (Event::RangeStop);
1087 _clear_event_type (Event::RangeLocate);
1093 list<AudioRange>::size_type sz = current_audio_range.size();
1097 list<AudioRange>::iterator i = current_audio_range.begin();
1098 list<AudioRange>::iterator next;
1100 while (i != current_audio_range.end()) {
1105 /* locating/stopping is subject to delays for declicking.
1108 jack_nframes_t requested_frame = (*i).end;
1110 if (requested_frame > current_block_size) {
1111 requested_frame -= current_block_size;
1113 requested_frame = 0;
1116 if (next == current_audio_range.end()) {
1117 ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
1119 ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
1127 } else if (sz == 1) {
1129 ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
1134 /* now start rolling at the right place */
1136 ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false);
1141 Session::request_bounded_roll (jack_nframes_t start, jack_nframes_t end)
1144 Event *ev = new Event (Event::StopOnce, Event::Replace, Event::Immediate, end, 0.0);
1146 request_locate (start, true);
1150 Session::engine_halted ()
1152 /* there will be no more calls to process(), so
1153 we'd better clean up for ourselves, right now.
1155 but first, make sure the butler is out of
1159 atomic_set (&butler_should_do_transport_work, 0);
1160 post_transport_work = PostTransportWork (0);
1163 realtime_stop (false);
1164 non_realtime_stop (false);
1165 transport_sub_state = 0;
1167 TransportStateChange (); /* EMIT SIGNAL */
1172 Session::xrun_recovery ()
1174 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1176 HaltOnXrun (); /* EMIT SIGNAL */
1178 /* it didn't actually halt, but we need
1179 to handle things in the same way.
1187 Session::update_latency_compensation (bool with_stop, bool abort)
1189 bool update_jack = false;
1191 if (_state_of_the_state & Deletion) {
1195 RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
1196 RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
1197 _worst_track_latency = 0;
1199 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1201 (*i)->transport_stopped (abort, (post_transport_work & PostTransportLocate),
1202 (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
1205 jack_nframes_t old_latency = (*i)->signal_latency ();
1206 jack_nframes_t track_latency = (*i)->update_total_latency ();
1208 if (old_latency != track_latency) {
1212 if (!(*i)->hidden() && ((*i)->active())) {
1213 _worst_track_latency = max (_worst_track_latency, track_latency);
1217 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1218 (*i)->set_latency_delay (_worst_track_latency);
1221 /* tell JACK to play catch up */
1224 _engine.update_total_latencies ();
1227 set_worst_io_latencies (false);
1229 /* reflect any changes in latencies into capture offsets
1232 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1233 (*i)->set_capture_offset ();
1238 Session::update_latency_compensation_proxy (void* ignored)
1240 update_latency_compensation (false, false);