Make the session start/end location a single location (with start and end) rather...
[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 */
19
20 #include <cmath>
21 #include <cerrno>
22 #include <unistd.h>
23
24
25 #include "pbd/undo.h"
26 #include "pbd/error.h"
27 #include "pbd/enumwriter.h"
28 #include "pbd/pthread_utils.h"
29 #include "pbd/memento_command.h"
30
31 #include "midi++/mmc.h"
32 #include "midi++/port.h"
33
34 #include "ardour/ardour.h"
35 #include "ardour/audio_diskstream.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/auditioner.h"
38 #include "ardour/butler.h"
39 #include "ardour/debug.h"
40 #include "ardour/location.h"
41 #include "ardour/session.h"
42 #include "ardour/slave.h"
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace ARDOUR;
48 using namespace PBD;
49
50 void
51 Session::add_post_transport_work (PostTransportWork ptw)
52 {
53         PostTransportWork oldval;
54         PostTransportWork newval;
55         int tries = 0;
56
57         while (tries < 8) {
58                 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
59                 newval = PostTransportWork (oldval | ptw);
60                 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
61                         /* success */
62                         return;
63                 }
64         }
65
66         error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
67 }
68
69 void
70 Session::request_input_change_handling ()
71 {
72         if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
73                 SessionEvent* ev = new SessionEvent (SessionEvent::InputConfigurationChange, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
74                 queue_event (ev);
75         }
76 }
77
78 void
79 Session::request_sync_source (Slave* new_slave)
80 {
81         SessionEvent* ev = new SessionEvent (SessionEvent::SetSyncSource, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
82         bool seamless;
83
84         seamless = Config->get_seamless_loop ();
85
86         if (dynamic_cast<JACK_Slave*>(new_slave)) {
87                 /* JACK cannot support seamless looping at present */
88                 Config->set_seamless_loop (false);
89         } else {
90                 /* reset to whatever the value was before we last switched slaves */
91                 Config->set_seamless_loop (_was_seamless);
92         }
93
94         /* save value of seamless from before the switch */
95         _was_seamless = seamless;
96
97         ev->slave = new_slave;
98         queue_event (ev);
99 }
100
101 void
102 Session::request_transport_speed (double speed)
103 {
104         SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
105         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1\n", speed));
106         queue_event (ev);
107 }
108
109 void
110 Session::request_diskstream_speed (Diskstream& ds, double speed)
111 {
112         SessionEvent* ev = new SessionEvent (SessionEvent::SetDiskstreamSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
113         ev->set_ptr (&ds);
114         queue_event (ev);
115 }
116
117 void
118 Session::request_stop (bool abort, bool clear_state)
119 {
120         SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0, abort, clear_state);
121         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport stop, abort = %1, clear state = %2\n", abort, clear_state));
122         queue_event (ev);
123 }
124
125 void
126 Session::request_locate (nframes_t target_frame, bool with_roll)
127 {
128         SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, false);
129         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_frame));
130         queue_event (ev);
131 }
132
133 void
134 Session::force_locate (nframes64_t target_frame, bool with_roll)
135 {
136         SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, true);
137         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_frame));
138         queue_event (ev);
139 }
140
141 void
142 Session::request_play_loop (bool yn, bool leave_rolling)
143 {
144         SessionEvent* ev;
145         Location *location = _locations.auto_loop_location();
146
147         if (location == 0 && yn) {
148                 error << _("Cannot loop - no loop range defined")
149                       << endmsg;
150                 return;
151         }
152
153         ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0), yn);
154         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, leave rolling ? %2\n", yn, leave_rolling));
155         queue_event (ev);
156
157         if (!leave_rolling && !yn && Config->get_seamless_loop() && transport_rolling()) {
158                 // request an immediate locate to refresh the diskstreams
159                 // after disabling looping
160                 request_locate (_transport_frame-1, false);
161         }
162 }
163
164 void
165 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
166 {
167         SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
168         if (range) {
169                 ev->audio_range = *range;
170         } else {
171                 ev->audio_range.clear ();
172         }
173         DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
174         queue_event (ev);
175 }
176
177 void
178 Session::realtime_stop (bool abort, bool clear_state)
179 {
180         DEBUG_TRACE (DEBUG::Transport, "realtime stop\n");
181         PostTransportWork todo = PostTransportWork (0);
182
183         /* assume that when we start, we'll be moving forwards */
184
185         // FIXME: where should this really be? [DR]
186         //send_full_time_code();
187         deliver_mmc (MIDI::MachineControl::cmdStop, 0);
188         deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
189
190         if (_transport_speed < 0.0f) {
191                 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
192         } else {
193                 todo = PostTransportWork (todo | PostTransportStop);
194         }
195
196         if (actively_recording()) {
197
198                 /* move the transport position back to where the
199                    request for a stop was noticed. we rolled
200                    past that point to pick up delayed input (and/or to delick)
201                 */
202
203                 if (_worst_output_latency > current_block_size) {
204                         /* we rolled past the stop point to pick up data that had
205                            not yet arrived. move back to where the stop occured.
206                         */
207                         decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size));
208                 } else {
209                         decrement_transport_position (current_block_size);
210                 }
211
212                 /* the duration change is not guaranteed to have happened, but is likely */
213
214                 todo = PostTransportWork (todo | PostTransportDuration);
215         }
216
217         if (abort) {
218                 todo = PostTransportWork (todo | PostTransportAbort);
219         }
220
221         if (clear_state) {
222                 todo = PostTransportWork (todo | PostTransportClearSubstate);
223         }
224
225         if (todo) {
226                 add_post_transport_work (todo);
227         }
228
229         _clear_event_type (SessionEvent::StopOnce);
230         _clear_event_type (SessionEvent::RangeStop);
231         _clear_event_type (SessionEvent::RangeLocate);
232
233         disable_record (true);
234
235         reset_slave_state ();
236
237         _transport_speed = 0;
238         _target_transport_speed = 0;
239
240         if (config.get_use_video_sync()) {
241                 waiting_for_sync_offset = true;
242         }
243
244         transport_sub_state = ((!config.get_external_sync()&& config.get_auto_return()) ? AutoReturning : 0);
245 }
246
247 void
248 Session::butler_transport_work ()
249 {
250   restart:
251         bool finished;
252         PostTransportWork ptw;
253         boost::shared_ptr<RouteList> r = routes.reader ();
254         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
255
256         int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
257         finished = true;
258         ptw = post_transport_work();
259
260         DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1\n", enum_2_string (ptw)));
261                      
262         if (ptw & PostTransportCurveRealloc) {
263                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
264                         (*i)->curve_reallocate();
265                 }
266         }
267
268         if (ptw & PostTransportInputChange) {
269                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
270                         (*i)->non_realtime_input_change ();
271                 }
272         }
273
274         if (ptw & PostTransportSpeed) {
275                 non_realtime_set_speed ();
276         }
277
278         if (ptw & PostTransportReverse) {
279
280                 clear_clicks();
281                 cumulative_rf_motion = 0;
282                 reset_rf_scale (0);
283
284                 /* don't seek if locate will take care of that in non_realtime_stop() */
285
286                 if (!(ptw & PostTransportLocate)) {
287
288                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
289                                 if (!(*i)->hidden()) {
290                                         (*i)->non_realtime_locate (_transport_frame);
291                                 }
292                                 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
293                                         /* new request, stop seeking, and start again */
294                                         g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
295                                         goto restart;
296                                 }
297                         }
298                 }
299         }
300
301         if (ptw & PostTransportLocate) {
302                 non_realtime_locate ();
303         }
304
305         if (ptw & PostTransportStop) {
306                 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
307                 if (!finished) {
308                         g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
309                         goto restart;
310                 }
311         }
312
313         if (ptw & PostTransportOverWrite) {
314                 non_realtime_overwrite (on_entry, finished);
315                 if (!finished) {
316                         g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
317                         goto restart;
318                 }
319         }
320
321         if (ptw & PostTransportAudition) {
322                 non_realtime_set_audition ();
323         }
324
325         g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
326 }
327
328 void
329 Session::non_realtime_set_speed ()
330 {
331         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
332
333         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
334                 (*i)->non_realtime_set_speed ();
335         }
336 }
337
338 void
339 Session::non_realtime_overwrite (int on_entry, bool& finished)
340 {
341         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
342
343         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
344                 if ((*i)->pending_overwrite) {
345                         (*i)->overwrite_existing_buffers ();
346                 }
347                 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
348                         finished = false;
349                         return;
350                 }
351         }
352 }
353
354
355 void
356 Session::non_realtime_locate ()
357 {
358         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
359
360         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
361                 (*i)->non_realtime_locate (_transport_frame);
362         }
363 }
364
365
366 void
367 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
368 {
369         struct tm* now;
370         time_t     xnow;
371         bool       did_record;
372         bool       saved;
373         PostTransportWork ptw = post_transport_work();
374
375         did_record = false;
376         saved = false;
377
378         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
379
380         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
381                 if ((*i)->get_captured_frames () != 0) {
382                         did_record = true;
383                         break;
384                 }
385         }
386
387         /* stop and locate are merged here because they share a lot of common stuff */
388
389         time (&xnow);
390         now = localtime (&xnow);
391
392         if (auditioner) {
393                 auditioner->cancel_audition ();
394         }
395
396         clear_clicks();
397         cumulative_rf_motion = 0;
398         reset_rf_scale (0);
399
400         if (did_record) {
401                 begin_reversible_command ("capture");
402
403                 Location* loc = _locations.session_range_location();
404                 bool change_end = false;
405
406                 if (_transport_frame < loc->end()) {
407
408                         /* stopped recording before current end */
409
410                         if (config.get_end_marker_is_free()) {
411
412                                 /* first capture for this session, move end back to where we are */
413
414                                 change_end = true;
415                         }
416
417                 } else if (_transport_frame > loc->end()) {
418
419                         /* stopped recording after the current end, extend it */
420
421                         change_end = true;
422                 }
423
424                 if (change_end) {
425                         XMLNode &before = loc->get_state();
426                         loc->set_end(_transport_frame);
427                         XMLNode &after = loc->get_state();
428                         add_command (new MementoCommand<Location>(*loc, &before, &after));
429                 }
430
431                 config.set_end_marker_is_free (false);
432                 _have_captured = true;
433         }
434
435         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
436                 (*i)->transport_stopped (*now, xnow, abort);
437         }
438
439         boost::shared_ptr<RouteList> r = routes.reader ();
440
441         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
442                 if (!(*i)->is_hidden()) {
443                         (*i)->set_pending_declick (0);
444                 }
445         }
446
447         if (did_record) {
448                 commit_reversible_command ();
449         }
450
451         if (_engine.running()) {
452                 update_latency_compensation (true, abort);
453         }
454
455         bool const auto_return_enabled =
456                 (!config.get_external_sync() && config.get_auto_return());
457
458         if (auto_return_enabled ||
459             (ptw & PostTransportLocate) ||
460             (_requested_return_frame >= 0) ||
461             synced_to_jack()) {
462
463                 if (pending_locate_flush) {
464                         flush_all_inserts ();
465                 }
466
467                 if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) &&
468                     !(ptw & PostTransportLocate)) {
469
470         /* no explicit locate queued */
471
472                         bool do_locate = false;
473
474                         if (_requested_return_frame >= 0) {
475
476                                 /* explicit return request pre-queued in event list. overrides everything else */
477                                 
478                                 cerr << "explicit auto-return to " << _requested_return_frame << endl;
479
480                                 _transport_frame = _requested_return_frame;
481                                 do_locate = true;
482
483                         } else {
484                                 if (config.get_auto_return()) {
485
486                                         if (play_loop) {
487
488                                                 /* don't try to handle loop play when synced to JACK */
489
490                                                 if (!synced_to_jack()) {
491
492                                                         Location *location = _locations.auto_loop_location();
493                                                         
494                                                         if (location != 0) {
495                                                                 _transport_frame = location->start();
496                                                         } else {
497                                                                 _transport_frame = _last_roll_location;
498                                                         }
499                                                         do_locate = true;
500                                                 }
501
502                                         } else if (_play_range) {
503
504                                                 /* return to start of range */
505
506                                                 if (!current_audio_range.empty()) {
507                                                         _transport_frame = current_audio_range.front().start;
508                                                         do_locate = true;
509                                                 }
510
511                                         } else {
512                                                 
513                                                 /* regular auto-return */
514                                                 
515                                                 _transport_frame = _last_roll_location;
516                                                 do_locate = true;
517                                         }
518                                 } 
519                         }
520
521                         _requested_return_frame = -1;                   
522
523                         if (do_locate) {
524                                 _engine.transport_locate (_transport_frame);
525                         }
526                 } 
527
528         }
529
530         /* do this before seeking, because otherwise the Diskstreams will do the wrong thing in seamless loop mode.
531         */
532
533         if (ptw & PostTransportClearSubstate) {
534                 _play_range = false;
535                 unset_play_loop ();
536         }
537
538         /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
539
540
541         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
542                 if (!(*i)->hidden()) {
543                         (*i)->non_realtime_locate (_transport_frame);
544                 }
545                 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
546                         finished = false;
547                         /* we will be back */
548                         return;
549                 }
550         }
551
552         have_looped = false;
553
554         send_full_time_code (0);
555         deliver_mmc (MIDI::MachineControl::cmdStop, 0);
556         deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
557
558         if ((ptw & PostTransportLocate) && get_record_enabled()) {
559                 /* capture start has been changed, so save pending state */
560                 save_state ("", true);
561                 saved = true;
562         }
563
564         /* always try to get rid of this */
565
566         remove_pending_capture_state ();
567
568         /* save the current state of things if appropriate */
569
570         if (did_record && !saved) {
571                 save_state (_current_snapshot_name);
572         }
573
574         if (ptw & PostTransportDuration) {
575                 DurationChanged (); /* EMIT SIGNAL */
576         }
577
578         if (ptw & PostTransportStop) {
579                 _play_range = false;
580                 play_loop = false;
581         }
582
583         // can't cast away volatile so copy and emit that
584         nframes64_t tframe = _transport_frame;
585         PositionChanged (tframe); /* EMIT SIGNAL */
586         TransportStateChange (); /* EMIT SIGNAL */
587
588         /* and start it up again if relevant */
589
590         if ((ptw & PostTransportLocate) && !config.get_external_sync() && pending_locate_roll) {
591                 request_transport_speed (1.0);
592                 pending_locate_roll = false;
593         }
594 }
595
596 void
597 Session::check_declick_out ()
598 {
599         bool locate_required = transport_sub_state & PendingLocate;
600
601         /* this is called after a process() iteration. if PendingDeclickOut was set,
602            it means that we were waiting to declick the output (which has just been
603            done) before doing something else. this is where we do that "something else".
604
605            note: called from the audio thread.
606         */
607
608         if (transport_sub_state & PendingDeclickOut) {
609
610                 if (locate_required) {
611                         start_locate (pending_locate_frame, pending_locate_roll, pending_locate_flush);
612                         transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
613                 } else {
614                         stop_transport (pending_abort);
615                         transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
616                 }
617         }
618 }
619
620 void
621 Session::unset_play_loop ()
622 {
623         play_loop = false;
624         clear_events (SessionEvent::AutoLoop);
625         
626         // set all diskstreams to NOT use internal looping
627         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
628         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
629                 if (!(*i)->hidden()) {
630                         (*i)->set_loop (0);
631                 }
632         }
633 }
634
635 void
636 Session::set_play_loop (bool yn)
637 {
638         /* Called from event-handling context */
639
640         Location *loc;
641
642         if (yn == play_loop || (actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
643                 /* nothing to do, or can't change loop status while recording */
644                 return;
645         }
646         
647         set_dirty();
648         
649         if (yn && Config->get_seamless_loop() && synced_to_jack()) {
650                 warning << string_compose (_("Seamless looping cannot be supported while %1 is using JACK transport.\n"
651                                              "Recommend changing the configured options"), PROGRAM_NAME)
652                         << endmsg;
653                 return;
654         }
655         
656         if (yn) {
657
658                 play_loop = true;
659
660                 if (loc) {
661
662                         unset_play_range ();
663
664                         if (Config->get_seamless_loop()) {
665                                 // set all diskstreams to use internal looping
666                                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
667                                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
668                                         if (!(*i)->hidden()) {
669                                                 (*i)->set_loop (loc);
670                                         }
671                                 }
672                         }
673                         else {
674                                 // set all diskstreams to NOT use internal looping
675                                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
676                                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
677                                         if (!(*i)->hidden()) {
678                                                 (*i)->set_loop (0);
679                                         }
680                                 }
681                         }
682                         
683                         /* put the loop event into the event list */
684                         
685                         SessionEvent* event = new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f);
686                         merge_event (event);
687
688                         /* locate to start of loop and roll. If doing seamless loop, force a 
689                            locate+buffer refill even if we are positioned there already.
690                         */
691
692                         start_locate (loc->start(), true, true, false, Config->get_seamless_loop());
693                 }
694
695         } else {
696
697                 unset_play_loop ();
698         }
699
700         TransportStateChange ();
701 }
702 void
703 Session::flush_all_inserts ()
704 {
705         boost::shared_ptr<RouteList> r = routes.reader ();
706
707         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
708                 (*i)->flush_processors ();
709         }
710 }
711
712 void
713 Session::start_locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
714 {
715         if (synced_to_jack()) {
716
717                 double sp;
718                 nframes64_t pos;
719
720                 _slave->speed_and_position (sp, pos);
721
722                 if (target_frame != pos) {
723
724                         /* tell JACK to change transport position, and we will
725                            follow along later in ::follow_slave()
726                         */
727
728                         _engine.transport_locate (target_frame);
729
730                         if (sp != 1.0f && with_roll) {
731                                 _engine.transport_start ();
732                         }
733
734                 }
735
736         } else {
737                 locate (target_frame, with_roll, with_flush, with_loop, force);
738         }
739 }
740
741 int
742 Session::micro_locate (nframes_t distance)
743 {
744         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
745
746         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
747                 if (!(*i)->can_internal_playback_seek (distance)) {
748                         return -1;
749                 }
750         }
751
752         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
753                 (*i)->internal_playback_seek (distance);
754         }
755
756         _transport_frame += distance;
757         return 0;
758 }
759
760 void
761 Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
762 {
763         if (actively_recording() && !with_loop) {
764                 return;
765         }
766
767         if (!force && _transport_frame == target_frame && !loop_changing && !with_loop) {
768                 if (with_roll) {
769                         set_transport_speed (1.0, false);
770                 }
771                 loop_changing = false;
772                 return;
773         }
774
775         // Update Timecode time
776         // [DR] FIXME: find out exactly where this should go below
777         _transport_frame = target_frame;
778         timecode_time(_transport_frame, transmitting_timecode_time);
779         outbound_mtc_timecode_frame = _transport_frame;
780         next_quarter_frame_to_send = 0;
781
782         if (_transport_speed && (!with_loop || loop_changing)) {
783                 /* schedule a declick. we'll be called again when its done */
784
785                 if (!(transport_sub_state & PendingDeclickOut)) {
786                         transport_sub_state |= (PendingDeclickOut|PendingLocate);
787                         pending_locate_frame = target_frame;
788                         pending_locate_roll = with_roll;
789                         pending_locate_flush = with_flush;
790                         return;
791                 }
792         }
793
794         if (transport_rolling() && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) {
795                 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
796         }
797
798         if (force || !with_loop || loop_changing) {
799
800                 PostTransportWork todo = PostTransportLocate;
801
802                 if (with_roll) {
803                         todo = PostTransportWork (todo | PostTransportRoll);
804                 } 
805
806                 add_post_transport_work (todo);
807                 _butler->schedule_transport_work ();
808
809         } else {
810
811                 /* this is functionally what clear_clicks() does but with a tentative lock */
812
813                 Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
814
815                 if (clickm.locked()) {
816
817                         for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
818                                 delete *i;
819                         }
820
821                         clicks.clear ();
822                 }
823         }
824
825         if (with_roll) {
826                 /* switch from input if we're going to roll */
827                 if (Config->get_monitoring_model() == HardwareMonitoring) {
828
829                         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
830
831                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
832                                 if ((*i)->record_enabled ()) {
833                                         //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
834                                         (*i)->monitor_input (!config.get_auto_input());
835                                 }
836                         }
837                 }
838         } else {
839                 /* otherwise we're going to stop, so do the opposite */
840                 if (Config->get_monitoring_model() == HardwareMonitoring) {
841                         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
842
843                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
844                                 if ((*i)->record_enabled ()) {
845                                         //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
846                                         (*i)->monitor_input (true);
847                                 }
848                         }
849                 }
850         }
851
852         /* cancel looped playback if transport pos outside of loop range */
853         if (play_loop) {
854                 Location* al = _locations.auto_loop_location();
855
856                 if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
857                         // cancel looping directly, this is called from event handling context
858                         set_play_loop (false);
859                 }
860                 else if (al && _transport_frame == al->start()) {
861                         if (with_loop) {
862                                 // this is only necessary for seamless looping
863
864                                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
865
866                                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
867                                         if ((*i)->record_enabled ()) {
868                                                 // tell it we've looped, so it can deal with the record state
869                                                 (*i)->transport_looped(_transport_frame);
870                                         }
871                                 }
872                         }
873                         have_looped = true;
874                         TransportLooped(); // EMIT SIGNAL
875                 }
876         }
877
878         loop_changing = false;
879
880         _send_timecode_update = true;
881
882         Located (); /* EMIT SIGNAL */
883 }
884
885 /** Set the transport speed.
886  * @param speed New speed
887  * @param abort
888  */
889 void
890 Session::set_transport_speed (double speed, bool abort, bool clear_state)
891 {
892         DEBUG_TRACE (DEBUG::Transport, string_compose ("Set transport speed to %1, abort = %2 clear_state = %3, current = %4\n", speed, abort, clear_state, _transport_speed));
893
894         if (_transport_speed == speed) {
895                 return;
896         }
897
898         _target_transport_speed = fabs(speed);
899
900         /* 8.0 max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
901            and user needs. We really need CD-style "skip" playback for ffwd and rewind.
902         */
903
904         if (speed > 0) {
905                 speed = min (8.0, speed);
906         } else if (speed < 0) {
907                 speed = max (-8.0, speed);
908         }
909
910         if (transport_rolling() && speed == 0.0) {
911
912                 /* we are rolling and we want to stop */
913
914                 if (Config->get_monitoring_model() == HardwareMonitoring)
915                 {
916                         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
917
918                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
919                                 if ((*i)->record_enabled ()) {
920                                         //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
921                                         (*i)->monitor_input (true);
922                                 }
923                         }
924                 }
925
926                 if (synced_to_jack ()) {
927                         if (clear_state) {
928                                 /* do this here because our response to the slave won't 
929                                    take care of it.
930                                 */
931                                 _play_range = false;
932                                 unset_play_loop ();
933                         }
934                         _engine.transport_stop ();
935                 } else {
936                         stop_transport (abort);
937                 }
938
939         } else if (transport_stopped() && speed == 1.0) {
940
941                 /* we are stopped and we want to start rolling at speed 1 */
942
943                 if (Config->get_monitoring_model() == HardwareMonitoring) {
944
945                         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
946
947                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
948                                 if (config.get_auto_input() && (*i)->record_enabled ()) {
949                                         //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
950                                         (*i)->monitor_input (false);
951                                 }
952                         }
953                 }
954
955                 if (synced_to_jack()) {
956                         _engine.transport_start ();
957                 } else {
958                         start_transport ();
959                 }
960
961         } else {
962
963                 if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
964                         warning << string_compose (_("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
965                                                    PROGRAM_NAME)
966                                 << endmsg;
967                         return;
968                 }
969
970                 if (actively_recording()) {
971                         return;
972                 }
973
974                 if (speed > 0.0 && _transport_frame == current_end_frame()) {
975                         return;
976                 }
977
978                 if (speed < 0.0 && _transport_frame == 0) {
979                         return;
980                 }
981
982                 clear_clicks ();
983
984                 /* if we are reversing relative to the current speed, or relative to the speed
985                    before the last stop, then we have to do extra work.
986                 */
987                 
988                 PostTransportWork todo = PostTransportWork (0);
989
990                 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
991                         todo = PostTransportWork (todo | PostTransportReverse);
992                 }
993
994                 _last_transport_speed = _transport_speed;
995                 _transport_speed = speed;
996
997                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
998                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
999                         if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
1000                                 todo = PostTransportWork (todo | PostTransportSpeed);
1001                                 break;
1002                         }
1003                 }
1004
1005                 if (todo) {
1006                         add_post_transport_work (todo);
1007                         _butler->schedule_transport_work ();
1008                 }
1009         }
1010 }
1011
1012
1013 /** Stop the transport.  */
1014 void
1015 Session::stop_transport (bool abort, bool clear_state)
1016 {
1017         if (_transport_speed == 0.0f) {
1018                 return;
1019         }
1020
1021         if (actively_recording() && !(transport_sub_state & StopPendingCapture) && _worst_output_latency > current_block_size) {
1022
1023                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1024
1025                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1026                         (*i)->prepare_to_stop (_transport_frame);
1027                 }
1028
1029                 /* we need to capture the audio that has still not yet been received by the system
1030                    at the time the stop is requested, so we have to roll past that time.
1031
1032                    we want to declick before stopping, so schedule the autostop for one
1033                    block before the actual end. we'll declick in the subsequent block,
1034                    and then we'll really be stopped.
1035                 */
1036
1037                 SessionEvent *ev = new SessionEvent (SessionEvent::StopOnce, SessionEvent::Replace,
1038                                        _transport_frame + _worst_output_latency - current_block_size,
1039                                        0, 0, abort);
1040
1041                 merge_event (ev);
1042                 transport_sub_state |= StopPendingCapture;
1043                 pending_abort = abort;
1044                 return;
1045         }
1046
1047
1048         if ((transport_sub_state & PendingDeclickOut) == 0) {
1049
1050                 if (!(transport_sub_state & StopPendingCapture)) {
1051                         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1052                         
1053                         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1054                                 (*i)->prepare_to_stop (_transport_frame);
1055                         }
1056                 }
1057                 
1058                 transport_sub_state |= PendingDeclickOut;
1059                 /* we'll be called again after the declick */
1060                 pending_abort = abort;
1061                 return;
1062         }
1063
1064         realtime_stop (abort, clear_state);
1065         _butler->schedule_transport_work ();
1066 }
1067
1068 void
1069 Session::start_transport ()
1070 {
1071         _last_roll_location = _transport_frame;
1072         have_looped = false;
1073
1074         /* if record status is Enabled, move it to Recording. if its
1075            already Recording, move it to Disabled.
1076         */
1077
1078         switch (record_status()) {
1079         case Enabled:
1080                 if (!config.get_punch_in()) {
1081                         enable_record ();
1082                 }
1083                 break;
1084
1085         case Recording:
1086                 if (!play_loop) {
1087                         disable_record (false);
1088                 }
1089                 break;
1090
1091         default:
1092                 break;
1093         }
1094
1095         transport_sub_state |= PendingDeclickIn;
1096
1097         _transport_speed = 1.0;
1098         _target_transport_speed = 1.0;
1099
1100         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1101         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1102                 (*i)->realtime_set_speed ((*i)->speed(), true);
1103         }
1104
1105         deliver_mmc(MIDI::MachineControl::cmdDeferredPlay, _transport_frame);
1106
1107         TransportStateChange (); /* EMIT SIGNAL */
1108 }
1109
1110 /** Do any transport work in the audio thread that needs to be done after the
1111  * transport thread is finished.  Audio thread, realtime safe.
1112  */
1113 void
1114 Session::post_transport ()
1115 {
1116         PostTransportWork ptw = post_transport_work ();
1117
1118         if (ptw & PostTransportAudition) {
1119                 if (auditioner && auditioner->auditioning()) {
1120                         process_function = &Session::process_audition;
1121                 } else {
1122                         process_function = &Session::process_with_events;
1123                 }
1124         }
1125
1126         if (ptw & PostTransportStop) {
1127
1128                 transport_sub_state = 0;
1129         }
1130
1131         if (ptw & PostTransportLocate) {
1132
1133                 if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
1134                         start_transport ();
1135
1136                 } else {
1137                         transport_sub_state = 0;
1138                 }
1139         }
1140
1141         set_next_event ();
1142         /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
1143            know were handled ?
1144         */
1145         set_post_transport_work (PostTransportWork (0));
1146 }
1147
1148 void
1149 Session::reset_rf_scale (nframes_t motion)
1150 {
1151         cumulative_rf_motion += motion;
1152
1153         if (cumulative_rf_motion < 4 * _current_frame_rate) {
1154                 rf_scale = 1;
1155         } else if (cumulative_rf_motion < 8 * _current_frame_rate) {
1156                 rf_scale = 4;
1157         } else if (cumulative_rf_motion < 16 * _current_frame_rate) {
1158                 rf_scale = 10;
1159         } else {
1160                 rf_scale = 100;
1161         }
1162
1163         if (motion != 0) {
1164                 set_dirty();
1165         }
1166 }
1167
1168 void
1169 Session::use_sync_source (Slave* new_slave)
1170 {
1171         /* Runs in process() context */
1172
1173         bool non_rt_required = false;
1174
1175         /* XXX this deletion is problematic because we're in RT context */
1176
1177         delete _slave;
1178         _slave = new_slave;
1179
1180         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1181         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1182                 if (!(*i)->hidden()) {
1183                         if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
1184                                 non_rt_required = true;
1185                         }
1186                         (*i)->set_slaved (_slave != 0);
1187                 }
1188         }
1189
1190         if (non_rt_required) {
1191                 add_post_transport_work (PostTransportSpeed);
1192                 _butler->schedule_transport_work ();
1193         }
1194
1195         set_dirty();
1196 }
1197
1198 void
1199 Session::drop_sync_source ()
1200 {
1201         request_sync_source (0);
1202 }
1203
1204 void
1205 Session::switch_to_sync_source (SyncSource src)
1206 {
1207         Slave* new_slave;
1208
1209         DEBUG_TRACE (DEBUG::Slave, string_compose ("Setting up sync source %1\n", enum_2_string (src)));
1210
1211         switch (src) {
1212         case MTC:
1213                 if (_slave && dynamic_cast<MTC_Slave*>(_slave)) {
1214                         return;
1215                 }
1216
1217                 if (_mtc_port) {
1218                         try {
1219                                 new_slave = new MTC_Slave (*this, *_mtc_port);
1220                         }
1221
1222                         catch (failed_constructor& err) {
1223                                 return;
1224                         }
1225
1226                 } else {
1227                         error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
1228                         return;
1229                 }
1230                 break;
1231
1232         case MIDIClock:
1233                 if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
1234                         return;
1235                 }
1236
1237                 if (_midi_clock_port) {
1238                         try {
1239                                 new_slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24);
1240                         }
1241
1242                         catch (failed_constructor& err) {
1243                                 return;
1244                         }
1245
1246                 } else {
1247                         error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg;
1248                         return;
1249                 }
1250                 break;
1251
1252         case JACK:
1253                 if (_slave && dynamic_cast<JACK_Slave*>(_slave)) {
1254                         return;
1255                 }
1256
1257                 new_slave = new JACK_Slave (_engine.jack());
1258                 break;
1259                 
1260         default:
1261                 new_slave = 0;
1262                 break;
1263         };
1264
1265         request_sync_source (new_slave);
1266 }
1267
1268 void
1269 Session::reverse_diskstream_buffers ()
1270 {
1271         add_post_transport_work (PostTransportReverse);
1272         _butler->schedule_transport_work ();
1273 }
1274
1275 void
1276 Session::set_diskstream_speed (Diskstream* stream, double speed)
1277 {
1278         if (stream->realtime_set_speed (speed, false)) {
1279                 add_post_transport_work (PostTransportSpeed);
1280                 _butler->schedule_transport_work ();
1281                 set_dirty ();
1282         }
1283 }
1284
1285 void
1286 Session::unset_play_range ()
1287 {
1288         _play_range = false;
1289         _clear_event_type (SessionEvent::RangeStop);
1290         _clear_event_type (SessionEvent::RangeLocate);
1291 }
1292
1293 void
1294 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1295 {
1296         SessionEvent* ev;
1297
1298         /* Called from event-processing context */
1299
1300         unset_play_range ();
1301         
1302         if (range.empty()) {
1303                 /* _play_range set to false in unset_play_range()
1304                  */
1305                 if (!leave_rolling) {
1306                         /* stop transport */
1307                         SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1308                         merge_event (ev);
1309                 }
1310                 return;
1311         }
1312
1313         _play_range = true;
1314
1315         /* cancel loop play */
1316         unset_play_loop ();
1317
1318         list<AudioRange>::size_type sz = range.size();
1319         
1320         if (sz > 1) {
1321                 
1322                 list<AudioRange>::iterator i = range.begin(); 
1323                 list<AudioRange>::iterator next;
1324                 
1325                 while (i != range.end()) {
1326                         
1327                         next = i;
1328                         ++next;
1329                         
1330                         /* locating/stopping is subject to delays for declicking.
1331                          */
1332                         
1333                         nframes_t requested_frame = (*i).end;
1334                         
1335                         if (requested_frame > current_block_size) {
1336                                 requested_frame -= current_block_size;
1337                         } else {
1338                                 requested_frame = 0;
1339                         }
1340                         
1341                         if (next == range.end()) {
1342                                 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_frame, 0, 0.0f);
1343                         } else {
1344                                 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_frame, (*next).start, 0.0f);
1345                         }
1346                         
1347                         merge_event (ev);
1348                         
1349                         i = next;
1350                 }
1351                 
1352         } else if (sz == 1) {
1353
1354                 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1355                 merge_event (ev);
1356                 
1357         } 
1358
1359         /* save range so we can do auto-return etc. */
1360
1361         current_audio_range = range;
1362
1363         /* now start rolling at the right place */
1364
1365         ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1366         merge_event (ev);
1367         
1368         TransportStateChange ();
1369 }
1370
1371 void
1372 Session::request_bounded_roll (nframes_t start, nframes_t end)
1373 {
1374         AudioRange ar (start, end, 0);
1375         list<AudioRange> lar;
1376
1377         lar.push_back (ar);
1378         request_play_range (&lar, true);
1379 }
1380 void
1381 Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
1382 {
1383         SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1384         ev->target2_frame = start;
1385         queue_event (ev);
1386 }
1387
1388 void
1389 Session::engine_halted ()
1390 {
1391         bool ignored;
1392
1393         /* there will be no more calls to process(), so
1394            we'd better clean up for ourselves, right now.
1395
1396            but first, make sure the butler is out of
1397            the picture.
1398         */
1399
1400         g_atomic_int_set (&_butler->should_do_transport_work, 0);
1401         set_post_transport_work (PostTransportWork (0));
1402         _butler->stop ();
1403
1404         realtime_stop (false, true);
1405         non_realtime_stop (false, 0, ignored);
1406         transport_sub_state = 0;
1407
1408         TransportStateChange (); /* EMIT SIGNAL */
1409 }
1410
1411
1412 void
1413 Session::xrun_recovery ()
1414 {
1415         // can't cast away volatile so copy and emit that
1416         nframes64_t tframe = _transport_frame;
1417         Xrun (tframe); //EMIT SIGNAL
1418
1419         if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1420
1421                 /* it didn't actually halt, but we need
1422                    to handle things in the same way.
1423                 */
1424
1425                 engine_halted();
1426         }
1427 }
1428
1429 void
1430 Session::route_processors_changed (RouteProcessorChange c)
1431 {
1432         if (c.type == RouteProcessorChange::MeterPointChange) {
1433                 return;
1434         }
1435
1436         update_latency_compensation (false, false);
1437         resort_routes ();
1438 }
1439
1440 void
1441 Session::update_latency_compensation (bool with_stop, bool abort)
1442 {
1443         bool update_jack = false;
1444         PostTransportWork ptw;
1445
1446         if (_state_of_the_state & Deletion) {
1447                 return;
1448         }
1449
1450         _worst_track_latency = 0;
1451         ptw = post_transport_work();
1452
1453 #undef DEBUG_LATENCY
1454 #ifdef DEBUG_LATENCY
1455         cerr << "\n---------------------------------\nUPDATE LATENCY\n";
1456 #endif
1457
1458         boost::shared_ptr<RouteList> r = routes.reader ();
1459
1460         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1461
1462                 if (with_stop) {
1463                         (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
1464                 }
1465
1466                 nframes_t old_latency = (*i)->output()->signal_latency ();
1467                 nframes_t track_latency = (*i)->update_total_latency ();
1468
1469                 if (old_latency != track_latency) {
1470                         (*i)->input()->update_port_total_latencies ();
1471                         (*i)->output()->update_port_total_latencies ();
1472                         update_jack = true;
1473                 }
1474
1475                 if (!(*i)->is_hidden() && ((*i)->active())) {
1476                         _worst_track_latency = max (_worst_track_latency, track_latency);
1477                 }
1478         }
1479
1480         if (update_jack) {
1481                 _engine.update_total_latencies ();
1482         }
1483
1484 #ifdef DEBUG_LATENCY
1485         cerr << "\tworst was " << _worst_track_latency << endl;
1486 #endif
1487
1488         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1489                 (*i)->set_latency_delay (_worst_track_latency);
1490         }
1491
1492         set_worst_io_latencies ();
1493
1494         /* reflect any changes in latencies into capture offsets
1495         */
1496
1497         boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1498
1499         for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1500                 (*i)->set_capture_offset ();
1501         }
1502 }
1503
1504 void
1505 Session::allow_auto_play (bool yn)
1506 {
1507         auto_play_legal = yn;
1508 }
1509
1510 void
1511 Session::reset_jack_connection (jack_client_t* jack)
1512 {
1513         JACK_Slave* js;
1514
1515         if (_slave && ((js = dynamic_cast<JACK_Slave*> (_slave)) != 0)) {
1516                 js->reset_client (jack);
1517         }
1518 }
1519
1520 bool
1521 Session::maybe_stop (nframes_t limit)
1522 {
1523        if ((_transport_speed > 0.0f && _transport_frame >= limit) || (_transport_speed < 0.0f && _transport_frame == 0)) {
1524                if (synced_to_jack () && config.get_jack_time_master ()) {
1525                        _engine.transport_stop ();
1526                } else if (!synced_to_jack ()) {
1527                        stop_transport ();
1528                }
1529                return true;
1530        }
1531        return false;
1532 }