a) completely refactor abstract UI code
[ardour.git] / libs / ardour / session_transport.cc
1 /*
2     Copyright (C) 1999-2003 Paul Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <cmath>
22 #include <cerrno>
23 #include <unistd.h>
24
25 #include <sigc++/bind.h>
26 #include <sigc++/retype.h>
27
28 #include <pbd/undo.h>
29 #include <pbd/error.h>
30 #include <pbd/lockmonitor.h>
31 #include <pbd/pthread_utils.h>
32
33 #include <midi++/mmc.h>
34 #include <midi++/port.h>
35
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>
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace ARDOUR;
48 using namespace sigc;
49
50 void
51 Session::request_input_change_handling ()
52 {
53         Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
54         queue_event (ev);
55 }
56
57 void
58 Session::request_slave_source (SlaveSource src, jack_nframes_t pos)
59 {
60         Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, pos, 0.0);
61
62         if (src == Session::JACK) {
63           /* could set_seamless_loop() be disposed of entirely?*/
64           set_seamless_loop (false);
65         } else {
66
67           set_seamless_loop (true);
68         }
69         ev->slave = src;
70         queue_event (ev);
71 }
72
73 void
74 Session::request_transport_speed (float speed)
75 {
76         Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
77         queue_event (ev);
78 }
79
80 void
81 Session::request_diskstream_speed (DiskStream& ds, float speed)
82 {
83         Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
84         ev->set_ptr (&ds);
85         queue_event (ev);
86 }
87
88 void
89 Session::request_stop (bool abort)
90 {
91         Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort);
92         queue_event (ev);
93 }
94
95 void
96 Session::request_locate (jack_nframes_t target_frame, bool with_roll)
97 {
98         Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, false);
99         queue_event (ev);
100 }
101
102 void
103 Session::force_locate (jack_nframes_t target_frame, bool with_roll)
104 {
105         Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true);
106         queue_event (ev);
107 }
108
109 void
110 Session::request_auto_loop (bool yn)
111 {
112         Event* ev;      
113         Location *location = _locations.auto_loop_location();
114
115         if (location == 0 && yn) {
116                 error << _("Cannot loop - no loop range defined")
117                       << endmsg;
118                 return;
119         }
120
121         ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
122         queue_event (ev);
123
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);
128         }
129 }
130
131 void
132 Session::set_seamless_loop (bool yn)
133 {
134         if (seamless_loop != yn) {
135                 seamless_loop = yn;
136
137                 if (auto_loop && transport_rolling()) {
138                         // to reset diskstreams etc
139                         request_auto_loop (true);
140                 }
141                 
142                 ControlChanged (SeamlessLoop); /* EMIT */
143         }
144 }
145
146 void
147 Session::realtime_stop (bool abort)
148 {
149         /* assume that when we start, we'll be moving forwards */
150
151         if (_transport_speed < 0.0f) {
152                 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse);
153         } else {
154                 post_transport_work = PostTransportWork (post_transport_work | PostTransportStop);
155         }
156
157         if (actively_recording()) {
158
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.
162                 */
163
164 #ifndef LEAVE_TRANSPORT_UNADJUSTED
165                 decrement_transport_position (_worst_output_latency);
166 #endif
167
168                 /* the duration change is not guaranteed to have happened, but is likely */
169
170                 post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
171         }
172
173         if (abort) {
174                 post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
175         }
176
177         _clear_event_type (Event::StopOnce);
178         _clear_event_type (Event::RangeStop);
179         _clear_event_type (Event::RangeLocate);
180
181         disable_record (true);
182
183         reset_slave_state ();
184                 
185         _transport_speed = 0;
186
187         transport_sub_state = (auto_return ? AutoReturning : 0);
188 }
189
190 void
191 Session::butler_transport_work ()
192 {
193         RWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
194         RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
195                 
196         if (post_transport_work & PostTransportCurveRealloc) {
197                 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
198                         (*i)->curve_reallocate();
199                 }
200         }
201
202         if (post_transport_work & PostTransportInputChange) {
203                 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
204                         (*i)->non_realtime_input_change ();
205                 }
206         }
207
208         if (post_transport_work & PostTransportSpeed) {
209                 non_realtime_set_speed ();
210         }
211
212         if (post_transport_work & PostTransportReverse) {
213
214
215                 clear_clicks();
216                 cumulative_rf_motion = 0;
217                 reset_rf_scale (0);
218
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()));
223                                 }
224                                 else {
225                                         (*i)->seek (_transport_frame);
226                                 }
227                         }
228                 }
229         }
230
231         if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
232                 non_realtime_stop (post_transport_work & PostTransportAbort);
233         }
234
235         if (post_transport_work & PostTransportOverWrite) {
236                 non_realtime_overwrite ();
237         }
238
239         if (post_transport_work & PostTransportAudition) {
240                 non_realtime_set_audition ();
241         }
242
243         atomic_dec (&butler_should_do_transport_work);
244 }
245
246 void
247 Session::non_realtime_set_speed ()
248 {
249         RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
250
251         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
252                 (*i)->non_realtime_set_speed ();
253         }
254 }
255
256 void
257 Session::non_realtime_overwrite ()
258 {
259         RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
260
261         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
262                 if ((*i)->pending_overwrite) {
263                         (*i)->overwrite_existing_buffers ();
264                 }
265         }
266 }
267
268 void
269 Session::non_realtime_stop (bool abort)
270 {
271         struct tm* now;
272         time_t     xnow;
273         bool       did_record;
274         
275         did_record = false;
276         
277         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
278                 if ((*i)->get_captured_frames () != 0) {
279                         did_record = true;
280                         break;
281                 }
282         }
283
284         /* stop and locate are merged here because they share a lot of common stuff */
285         
286         time (&xnow);
287         now = localtime (&xnow);
288
289         if (auditioner) {
290                 auditioner->cancel_audition ();
291         }
292
293         clear_clicks();
294         cumulative_rf_motion = 0;
295         reset_rf_scale (0);
296
297         if (did_record) {
298                 begin_reversible_command ("capture");
299                 
300                 Location* loc = _locations.end_location();
301                 bool change_end = false;
302
303                 if (_transport_frame < loc->end()) {
304
305                         /* stopped recording before current end */
306
307                         if (_end_location_is_free) {
308
309                                 /* first capture for this session, move end back to where we are */
310
311                                 change_end = true;
312                         } 
313
314                 } else if (_transport_frame > loc->end()) {
315                         
316                         /* stopped recording after the current end, extend it */
317
318                         change_end = true;
319                 }
320                 
321                 if (change_end) {
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)));
324                 }
325
326                 _end_location_is_free = false;
327                 _have_captured = true;
328         }
329
330         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
331                 (*i)->transport_stopped (*now, xnow, abort);
332         }
333         
334         for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
335                 if (!(*i)->hidden()) {
336                         (*i)->set_pending_declick (0);
337                 }
338         }
339
340         if (did_record) {
341                 commit_reversible_command ();
342         }       
343
344         if (_engine.running()) {
345                 update_latency_compensation (true, abort);
346         }
347
348         if (auto_return || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
349
350                 if (pending_locate_flush) {
351                         flush_all_redirects ();
352                 }
353
354                 if ((auto_return || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
355
356                         _transport_frame = last_stop_frame;
357
358                         if (synced_to_jack()) {
359                                 _engine.transport_locate (_transport_frame);
360                         }
361                 } 
362
363 #ifndef LEAVE_TRANSPORT_UNADJUSTED
364         }
365 #endif
366
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()));
371                                 }
372                                 else {
373                                         (*i)->seek (_transport_frame);
374                                 }
375                         }
376                 }
377
378                 deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
379
380 #ifdef LEAVE_TRANSPORT_UNADJUSTED
381         }
382 #endif
383
384         last_stop_frame = _transport_frame;
385
386         send_full_time_code ();
387         deliver_mmc (MIDI::MachineControl::cmdStop, 0);
388         deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
389
390         if (did_record) {
391
392                 /* XXX its a little odd that we're doing this here
393                    when realtime_stop(), which has already executed,
394                    will have done this.
395                 */
396
397                 if (!Config->get_latched_record_enable()) {
398                         atomic_set (&_record_status, Disabled);
399                 } else {
400                         atomic_set (&_record_status, Enabled);
401                 }
402                 RecordStateChanged (); /* emit signal */
403         }
404         
405         if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
406                 /* capture start has been changed, so save pending state */
407                 save_state ("", true);
408         }
409
410         /* always try to get rid of this */
411
412         remove_pending_capture_state ();
413         
414         /* save the current state of things if appropriate */
415
416         if (did_record) {
417                 save_state (_current_snapshot_name);
418         }
419
420         if (post_transport_work & PostTransportDuration) {
421                 DurationChanged (); /* EMIT SIGNAL */
422         }
423
424         if (post_transport_work & PostTransportStop) { 
425                 _play_range = false;
426
427                 /* do not turn off autoloop on stop */
428
429         }
430
431         PositionChanged (_transport_frame); /* EMIT SIGNAL */
432         TransportStateChange (); /* EMIT SIGNAL */
433
434         /* and start it up again if relevant */
435
436         if ((post_transport_work & PostTransportLocate) && _slave_type == None && pending_locate_roll) {
437                 request_transport_speed (1.0);
438                 pending_locate_roll = false;
439         }
440 }
441
442 void
443 Session::check_declick_out ()
444 {
445         bool locate_required = transport_sub_state & PendingLocate;
446
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".
450            
451            note: called from the audio thread.
452         */
453
454         if (transport_sub_state & PendingDeclickOut) {
455
456                 if (locate_required) {
457                         start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
458                         transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
459                 } else {
460                         stop_transport (pending_abort);
461                         transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
462                 }
463         }
464 }
465
466 void
467 Session::set_auto_loop (bool yn)
468 {
469         /* Called from event-handling context */
470         
471         if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
472                 return;
473         }
474         
475         set_dirty();
476
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")
480                         << endmsg;
481                 return;
482         }
483
484         
485         if ((auto_loop = yn)) {
486
487                 Location *loc;
488
489                 
490                 if ((loc = _locations.auto_loop_location()) != 0) {
491
492                         if (seamless_loop) {
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);
497                                         }
498                                 }
499                         }
500                         else {
501                                 // set all diskstreams to NOT use internal looping
502                                 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
503                                         if (!(*i)->hidden()) {
504                                                 (*i)->set_loop (0);
505                                         }
506                                 }
507                         }
508                         
509                         /* stick in the loop event */
510                         
511                         Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
512                         merge_event (event);
513
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());
517                                 merge_event (event);
518                         }
519                         else {
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());
522                                 merge_event (event);
523                         }
524                 }
525
526
527
528         } else {
529                 clear_events (Event::AutoLoop);
530
531                 // set all diskstreams to NOT use internal looping
532                 for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
533                         if (!(*i)->hidden()) {
534                                 (*i)->set_loop (0);
535                         }
536                 }
537                 
538         }
539         
540         ControlChanged (AutoLoop); /* EMIT SIGNAL */
541 }
542
543 void
544 Session::flush_all_redirects ()
545 {
546         for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
547                 (*i)->flush_redirects ();
548         }
549 }
550
551 void
552 Session::start_locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
553 {
554         if (synced_to_jack()) {
555
556                 float sp;
557                 jack_nframes_t pos;
558
559                 _slave->speed_and_position (sp, pos);
560
561                 if (target_frame != pos) {
562
563                         /* tell JACK to change transport position, and we will
564                            follow along later in ::follow_slave()
565                         */
566
567                         _engine.transport_locate (target_frame);
568
569                         if (sp != 1.0f && with_roll) {
570                                 _engine.transport_start ();
571                         }
572
573                 }
574
575         } else {
576
577                 locate (target_frame, with_roll, with_flush, with_loop);
578         }
579 }
580
581 void
582 Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
583 {
584         if (actively_recording()) {
585                 return;
586         }
587
588         if (_transport_frame == target_frame && !loop_changing && !with_loop) {
589                 if (with_roll) {
590                         set_transport_speed (1.0, false);
591                 }
592                 loop_changing = false;
593                 return;
594         }
595
596         _transport_frame = target_frame;
597
598         if (_transport_speed && (!with_loop || loop_changing)) {
599                 /* schedule a declick. we'll be called again when its done */
600
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;
606                         return;
607                 } 
608         }
609
610         if (transport_rolling() && !auto_play && !with_roll && !(synced_to_jack() && auto_loop)) {
611                 realtime_stop (false);
612         } 
613
614         if ( !with_loop || loop_changing) {
615
616                 post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
617                 
618                 if (with_roll) {
619                         post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll);
620                 }
621
622                 schedule_butler_transport_work ();
623
624         } else {
625
626                 /* this is functionally what clear_clicks() does but with a tentative lock */
627
628                 TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
629         
630                 if (clickm.locked()) {
631                         
632                         for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
633                                 delete *i;
634                         }
635                 
636                         clicks.clear ();
637                 }
638         }
639
640         if (with_roll) {
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"
646                         */
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);
652                                 }
653                         }
654                 }
655         } else {
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"
661                         */
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);
667                                 }
668                         }
669                 }
670         }
671
672         /* cancel autoloop if transport pos outside of loop range */
673         if (auto_loop) {
674                 Location* al = _locations.auto_loop_location();
675                 
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);
679                 }
680         }
681         
682         loop_changing = false;
683 }
684
685 void
686 Session::set_transport_speed (float speed, bool abort)
687 {
688         if (_transport_speed == speed) {
689                 return;
690         }
691
692         if (speed > 0) {
693                 speed = min (8.0f, speed);
694         } else if (speed < 0) {
695                 speed = max (-8.0f, speed);
696         }
697
698         if (transport_rolling() && speed == 0.0) {
699
700                 if (Config->get_use_hardware_monitoring())
701                 {
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"
705                         */
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);     
711                                 }
712                         }
713                 }
714
715                 if (synced_to_jack ()) {
716                         _engine.transport_stop ();
717                 } else {
718                         stop_transport (abort);
719                 }
720
721         } else if (transport_stopped() && speed == 1.0) {
722
723                 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
724                         return;
725                 }
726
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"
731                         */
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);    
737                                 }
738                         }
739                 }
740
741                 if (synced_to_jack()) {
742                         _engine.transport_start ();
743                 } else {
744                         start_transport ();
745                 }
746
747         } else {
748
749                 if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
750                         return;
751                 }
752
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")
755                                 << endmsg;
756                         return;
757                 }
758
759                 if (actively_recording()) {
760                         return;
761                 }
762
763                 if (speed > 0.0f && _transport_frame == current_end_frame()) {
764                         return;
765                 }
766
767                 if (speed < 0.0f && _transport_frame == 0) {
768                         return;
769                 }
770                 
771                 clear_clicks ();
772
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.
775                 */
776
777                 if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f)) {
778                         post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
779                 }
780                 
781                 _last_transport_speed = _transport_speed;
782                 _transport_speed = speed;
783                 
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);
787                         }
788                 }
789                 
790                 if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) {
791                         schedule_butler_transport_work ();
792                 }
793         }
794 }
795
796 void
797 Session::stop_transport (bool abort)
798 {
799         if (_transport_speed == 0.0f) {
800                 return;
801         }
802
803         if (actively_recording() && !(transport_sub_state & StopPendingCapture) && 
804             _worst_output_latency > current_block_size) 
805         {
806                 
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.
809
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.
813                 */
814                 
815                 Event *ev = new Event (Event::StopOnce, Event::Replace, 
816                                        _transport_frame + _worst_output_latency - current_block_size,
817                                        0, 0, abort);
818                 
819                 merge_event (ev);
820                 transport_sub_state |= StopPendingCapture;
821                 pending_abort = abort;
822                 return;
823         } 
824
825         if ((transport_sub_state & PendingDeclickOut) == 0) {
826                 transport_sub_state |= PendingDeclickOut;
827                 /* we'll be called again after the declick */
828                 return;
829         }
830
831         realtime_stop (abort);
832         schedule_butler_transport_work ();
833 }
834
835 void
836 Session::start_transport ()
837 {
838         _last_roll_location = _transport_frame;
839
840         /* if record status is Enabled, move it to Recording. if its
841            already Recording, move it to Disabled. 
842         */
843
844         switch (record_status()) {
845         case Enabled:
846                 if (!punch_in) {
847                         enable_record ();
848                 }
849                 break;
850
851         case Recording:
852                 disable_record (false);
853                 break;
854
855         default:
856                 break;
857         }
858
859         if (!synced_to_jack() || _exporting) {
860                 actually_start_transport ();
861         } else {
862                 waiting_to_start = true;
863         }
864 }
865
866 void
867 Session::actually_start_transport ()
868 {
869         waiting_to_start = false;
870
871         transport_sub_state |= PendingDeclickIn;
872         _transport_speed = 1.0;
873         
874         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
875                 (*i)->realtime_set_speed ((*i)->speed(), true);
876         }
877
878         send_mmc_in_another_thread (MIDI::MachineControl::cmdDeferredPlay, 0);
879         
880         TransportStateChange (); /* EMIT SIGNAL */
881 }
882
883 void
884 Session::post_transport ()
885 {
886         if (post_transport_work & PostTransportAudition) {
887                 if (auditioner && auditioner->active()) {
888                         process_function = &Session::process_audition;
889                 } else {
890                         process_function = &Session::process_with_events;
891                 }
892         }
893
894         if (post_transport_work & PostTransportStop) {
895
896                 transport_sub_state = 0;
897         }
898
899         if (post_transport_work & PostTransportLocate) {
900
901                 if ((auto_play && !_exporting) || (post_transport_work & PostTransportRoll)) {
902                         
903                         start_transport ();
904                         
905                 } else {
906                         transport_sub_state = 0;
907                 }
908         }
909
910         set_next_event ();
911
912         post_transport_work = PostTransportWork (0);
913 }
914
915 void
916 Session::set_rf_speed (float speed)
917 {
918         rf_speed = speed;
919         cumulative_rf_motion = 0;
920         reset_rf_scale (0);
921 }
922
923 void
924 Session::reset_rf_scale (jack_nframes_t motion)
925 {
926         cumulative_rf_motion += motion;
927
928         if (cumulative_rf_motion < 4 * _current_frame_rate) {
929                 rf_scale = 1;
930         } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
931                 rf_scale = 4;
932         } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
933                 rf_scale = 10;
934         } else {
935                 rf_scale = 100;
936         }
937
938         if (motion != 0) {
939                 set_dirty();
940         }
941 }
942
943 int
944 Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
945 {
946         bool reverse = false;
947         bool non_rt_required = false;
948
949         if (src == _slave_type) {
950                 return 0;
951         } 
952
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 */
957                 return 0;
958         }
959
960 //      if (src == JACK && Config->get_jack_time_master()) {
961 //              return -1;
962 //      }
963         
964         if (_slave) {
965                 delete _slave;
966                 _slave = 0;
967                 _slave_type = None;
968         }
969
970         if (_transport_speed < 0.0) {
971                 reverse = true;
972         }
973
974         switch (src) {
975         case None:
976                 stop_transport ();
977                 break;
978
979         case MTC:
980                 if (_mtc_port) {
981                         try {
982                                 _slave = new MTC_Slave (*this, *_mtc_port);
983                         }
984
985                         catch (failed_constructor& err) {
986                                 return -1;
987                         }
988
989                 } else {
990                         error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
991                         return -1;
992                 }
993                 _desired_transport_speed = _transport_speed;
994                 break;
995                 
996         case JACK:
997                 _slave = new JACK_Slave (_engine.jack());
998                 _desired_transport_speed = _transport_speed;
999                 break;
1000         };
1001         
1002         _slave_type = src;
1003
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;
1008                         }
1009                         (*i)->set_slaved (_slave);
1010                 }
1011         }
1012
1013         if (reverse) {
1014                 reverse_diskstream_buffers ();
1015         }
1016
1017         if (non_rt_required) {
1018                 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1019                 schedule_butler_transport_work ();
1020         }
1021
1022         set_dirty();
1023         ControlChanged (SlaveType); /* EMIT SIGNAL */
1024         
1025         return 0;
1026 }
1027
1028 void
1029 Session::reverse_diskstream_buffers ()
1030 {
1031         post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
1032         schedule_butler_transport_work ();
1033 }
1034
1035 void
1036 Session::set_diskstream_speed (DiskStream* stream, float speed)
1037 {
1038         if (stream->realtime_set_speed (speed, false)) {
1039                 post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
1040                 schedule_butler_transport_work ();
1041                 set_dirty ();
1042         }
1043 }
1044
1045 void
1046 Session::set_audio_range (list<AudioRange>& range)
1047 {
1048         Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f);
1049         ev->audio_range = range;
1050         queue_event (ev);
1051 }
1052
1053 void
1054 Session::request_play_range (bool yn)
1055 {
1056         Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, 0.0f, yn);
1057         queue_event (ev);
1058 }
1059
1060 void
1061 Session::set_play_range (bool yn)
1062 {
1063         /* Called from event-processing context */
1064
1065         if (_play_range != yn) {
1066                 _play_range = yn;
1067                 setup_auto_play ();
1068
1069                 if (!_play_range) {
1070                         /* stop transport */
1071                         Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
1072                         merge_event (ev);
1073                 }
1074
1075                  ControlChanged (PlayRange); /* EMIT SIGNAL */
1076         }
1077 }
1078
1079 void
1080 Session::setup_auto_play ()
1081 {
1082         /* Called from event-processing context */
1083
1084         Event* ev;
1085         
1086         _clear_event_type (Event::RangeStop);
1087         _clear_event_type (Event::RangeLocate);
1088
1089         if (!_play_range) {
1090                 return;
1091         }
1092
1093         list<AudioRange>::size_type sz = current_audio_range.size();
1094         
1095         if (sz > 1) {
1096                 
1097                 list<AudioRange>::iterator i = current_audio_range.begin(); 
1098                 list<AudioRange>::iterator next;
1099                 
1100                 while (i != current_audio_range.end()) {
1101                         
1102                         next = i;
1103                         ++next;
1104                         
1105                         /* locating/stopping is subject to delays for declicking.
1106                          */
1107                         
1108                         jack_nframes_t requested_frame = (*i).end;
1109                         
1110                         if (requested_frame > current_block_size) {
1111                                 requested_frame -= current_block_size;
1112                         } else {
1113                                 requested_frame = 0;
1114                         }
1115                         
1116                         if (next == current_audio_range.end()) {
1117                                 ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
1118                         } else {
1119                                 ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
1120                         }
1121                         
1122                         merge_event (ev);
1123                         
1124                         i = next;
1125                 }
1126                 
1127         } else if (sz == 1) {
1128                 
1129                 ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
1130                 merge_event (ev);
1131                 
1132         } 
1133
1134         /* now start rolling at the right place */
1135         
1136         ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false);
1137         merge_event (ev);
1138 }
1139
1140 void
1141 Session::request_bounded_roll (jack_nframes_t start, jack_nframes_t end)
1142 {
1143         request_stop ();
1144         Event *ev = new Event (Event::StopOnce, Event::Replace, Event::Immediate, end, 0.0);
1145         queue_event (ev);
1146         request_locate (start, true);
1147 }
1148
1149 void
1150 Session::engine_halted ()
1151 {
1152         /* there will be no more calls to process(), so
1153            we'd better clean up for ourselves, right now.
1154
1155            but first, make sure the butler is out of 
1156            the picture.
1157         */
1158
1159         atomic_set (&butler_should_do_transport_work, 0);
1160         post_transport_work = PostTransportWork (0);
1161         stop_butler ();
1162         
1163         realtime_stop (false);
1164         non_realtime_stop (false);
1165         transport_sub_state = 0;
1166
1167         TransportStateChange (); /* EMIT SIGNAL */
1168 }
1169
1170
1171 void
1172 Session::xrun_recovery ()
1173 {
1174         if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1175
1176                  HaltOnXrun (); /* EMIT SIGNAL */
1177
1178                 /* it didn't actually halt, but we need
1179                    to handle things in the same way.
1180                 */
1181
1182                 engine_halted();
1183         } 
1184 }
1185
1186 void
1187 Session::update_latency_compensation (bool with_stop, bool abort)
1188 {
1189         bool update_jack = false;
1190
1191         if (_state_of_the_state & Deletion) {
1192                 return;
1193         }
1194
1195         RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
1196         RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
1197         _worst_track_latency = 0;
1198
1199         for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1200                 if (with_stop) {
1201                         (*i)->transport_stopped (abort, (post_transport_work & PostTransportLocate), 
1202                                                  (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
1203                 }
1204
1205                 jack_nframes_t old_latency = (*i)->signal_latency ();
1206                 jack_nframes_t track_latency = (*i)->update_total_latency ();
1207
1208                 if (old_latency != track_latency) {
1209                         update_jack = true;
1210                 }
1211                 
1212                 if (!(*i)->hidden() && ((*i)->active())) {
1213                         _worst_track_latency = max (_worst_track_latency, track_latency);
1214                 }
1215         }
1216
1217         for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1218                 (*i)->set_latency_delay (_worst_track_latency);
1219         }
1220
1221         /* tell JACK to play catch up */
1222
1223         if (update_jack) {
1224                 _engine.update_total_latencies ();
1225         }
1226
1227         set_worst_io_latencies (false);
1228
1229         /* reflect any changes in latencies into capture offsets
1230         */
1231         
1232         for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
1233                 (*i)->set_capture_offset ();
1234         }
1235 }
1236
1237 void
1238 Session::update_latency_compensation_proxy (void* ignored)
1239 {
1240         update_latency_compensation (false, false);
1241 }