more tweaks to latency measurement
[ardour.git] / libs / ardour / audioengine.cc
1 /*
2     Copyright (C) 2002 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 <unistd.h>
21 #include <cerrno>
22 #include <vector>
23 #include <exception>
24 #include <stdexcept>
25 #include <sstream>
26
27 #include <glibmm/timer.h>
28 #include <glibmm/pattern.h>
29 #include <glibmm/module.h>
30
31 #include "pbd/epa.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/stacktrace.h"
35 #include "pbd/unknown_type.h"
36
37 #include <jack/weakjack.h>
38
39 #include "midi++/port.h"
40 #include "midi++/mmc.h"
41
42 #include "ardour/async_midi_port.h"
43 #include "ardour/audio_port.h"
44 #include "ardour/audio_backend.h"
45 #include "ardour/audioengine.h"
46 #include "ardour/backend_search_path.h"
47 #include "ardour/buffer.h"
48 #include "ardour/cycle_timer.h"
49 #include "ardour/internal_send.h"
50 #include "ardour/meter.h"
51 #include "ardour/midi_port.h"
52 #include "ardour/midiport_manager.h"
53 #include "ardour/mtdm.h"
54 #include "ardour/port.h"
55 #include "ardour/process_thread.h"
56 #include "ardour/session.h"
57
58 #include "i18n.h"
59
60 using namespace std;
61 using namespace ARDOUR;
62 using namespace PBD;
63
64 gint AudioEngine::m_meter_exit;
65 AudioEngine* AudioEngine::_instance = 0;
66
67 AudioEngine::AudioEngine ()
68         : session_remove_pending (false)
69         , session_removal_countdown (-1)
70         , _running (false)
71         , _freewheeling (false)
72         , monitor_check_interval (INT32_MAX)
73         , last_monitor_check (0)
74         , _processed_frames (0)
75         , m_meter_thread (0)
76         , _main_thread (0)
77         , _mtdm (0)
78         , _measuring_latency (false)
79         , _latency_input_port (0)
80         , _latency_output_port (0)
81         , _latency_flush_frames (0)
82 {
83         g_atomic_int_set (&m_meter_exit, 0);
84         discover_backends ();
85 }
86
87 AudioEngine::~AudioEngine ()
88 {
89         drop_backend ();
90
91         config_connection.disconnect ();
92
93         {
94                 Glib::Threads::Mutex::Lock tm (_process_lock);
95                 session_removed.signal ();
96                 stop_metering_thread ();
97         }
98 }
99
100 AudioEngine*
101 AudioEngine::create ()
102 {
103         if (_instance) {
104                 return _instance;
105         }
106
107         _instance = new AudioEngine ();
108         
109         return _instance;
110 }
111
112 void
113 _thread_init_callback (void * /*arg*/)
114 {
115         /* make sure that anybody who needs to know about this thread
116            knows about it.
117         */
118
119         pthread_set_name (X_("audioengine"));
120
121         PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Audioengine"), 4096);
122         PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("Audioengine"), 128);
123
124         SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
125
126         AsyncMIDIPort::set_process_thread (pthread_self());
127 }
128
129 void
130 AudioEngine::split_cycle (pframes_t offset)
131 {
132         /* caller must hold process lock */
133
134         Port::increment_global_port_buffer_offset (offset);
135
136         /* tell all Ports that we're going to start a new (split) cycle */
137
138         boost::shared_ptr<Ports> p = ports.reader();
139
140         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
141                 i->second->cycle_split ();
142         }
143 }
144
145 int
146 AudioEngine::sample_rate_change (pframes_t nframes)
147 {
148         /* check for monitor input change every 1/10th of second */
149
150         monitor_check_interval = nframes / 10;
151         last_monitor_check = 0;
152
153         if (_session) {
154                 _session->set_frame_rate (nframes);
155         }
156
157         SampleRateChanged (nframes); /* EMIT SIGNAL */
158
159         return 0;
160 }
161
162 int 
163 AudioEngine::buffer_size_change (pframes_t bufsiz)
164 {
165         if (_session) {
166                 _session->set_block_size (bufsiz);
167                 last_monitor_check = 0;
168         }
169
170         return 0;
171 }
172
173 /** Method called by our ::process_thread when there is work to be done.
174  *  @param nframes Number of frames to process.
175  */
176 int
177 AudioEngine::process_callback (pframes_t nframes)
178 {
179         Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
180
181         PT_TIMING_REF;
182         PT_TIMING_CHECK (1);
183
184         /// The number of frames that will have been processed when we've finished
185         pframes_t next_processed_frames;
186
187         /* handle wrap around of total frames counter */
188
189         if (max_framepos - _processed_frames < nframes) {
190                 next_processed_frames = nframes - (max_framepos - _processed_frames);
191         } else {
192                 next_processed_frames = _processed_frames + nframes;
193         }
194
195         if (!tm.locked()) {
196                 /* return having done nothing */
197                 _processed_frames = next_processed_frames;
198                 return 0;
199         }
200
201         /* If measuring latency, do it now and get out of here */
202
203         if (_measuring_latency && _mtdm) {
204                 // PortManager::cycle_start (nframes);
205                 // PortManager::silence (nframes);
206
207                 if (_latency_input_port && _latency_output_port) {
208                         PortEngine& pe (port_engine());
209
210                         Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
211                         Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
212
213                         _mtdm->process (nframes, in, out);
214                 }
215
216                 // PortManager::cycle_end (nframes);
217                 return 0;
218
219         } else if (_latency_flush_frames) {
220                 
221                 /* wait for the appropriate duration for the MTDM signal to
222                  * drain from the ports before we revert to normal behaviour.
223                  */
224
225                 PortManager::cycle_start (nframes);
226                 PortManager::silence (nframes);
227                 PortManager::cycle_end (nframes);
228                 
229                 if (_latency_flush_frames > nframes) {
230                         _latency_flush_frames -= nframes;
231                 } else {
232                         _latency_flush_frames = 0;
233                 }
234
235                 return 0;
236         }
237
238         if (session_remove_pending) {
239
240                 /* perform the actual session removal */
241
242                 if (session_removal_countdown < 0) {
243
244                         /* fade out over 1 second */
245                         session_removal_countdown = sample_rate()/2;
246                         session_removal_gain = 1.0;
247                         session_removal_gain_step = 1.0/session_removal_countdown;
248
249                 } else if (session_removal_countdown > 0) {
250
251                         /* we'll be fading audio out.
252                            
253                            if this is the last time we do this as part 
254                            of session removal, do a MIDI panic now
255                            to get MIDI stopped. This relies on the fact
256                            that "immediate data" (aka "out of band data") from
257                            MIDI tracks is *appended* after any other data, 
258                            so that it emerges after any outbound note ons, etc.
259                         */
260
261                         if (session_removal_countdown <= nframes) {
262                                 _session->midi_panic ();
263                         }
264
265                 } else {
266                         /* fade out done */
267                         _session = 0;
268                         session_removal_countdown = -1; // reset to "not in progress"
269                         session_remove_pending = false;
270                         session_removed.signal(); // wakes up thread that initiated session removal
271                 }
272         }
273
274         if (_session == 0) {
275
276                 if (!_freewheeling) {
277                         PortManager::cycle_start (nframes);
278                         PortManager::cycle_end (nframes);
279                 }
280
281                 _processed_frames = next_processed_frames;
282
283                 return 0;
284         }
285
286         /* tell all relevant objects that we're starting a new cycle */
287
288         InternalSend::CycleStart (nframes);
289
290         /* tell all Ports that we're starting a new cycle */
291
292         PortManager::cycle_start (nframes);
293
294         /* test if we are freewheeling and there are freewheel signals connected.
295            ardour should act normally even when freewheeling unless /it/ is
296            exporting (which is what Freewheel.empty() tests for).
297         */
298
299         if (_freewheeling && !Freewheel.empty()) {
300                 Freewheel (nframes);
301         } else {
302                 if (_session) {
303                         _session->process (nframes);
304                 }
305         }
306
307         if (_freewheeling) {
308                 return 0;
309         }
310
311         if (!_running) {
312                 _processed_frames = next_processed_frames;
313                 return 0;
314         }
315
316         if (last_monitor_check + monitor_check_interval < next_processed_frames) {
317                 
318                 PortManager::check_monitoring ();
319                 last_monitor_check = next_processed_frames;
320         }
321
322         if (_session->silent()) {
323                 PortManager::silence (nframes);
324         }
325
326         if (session_remove_pending && session_removal_countdown) {
327
328                 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
329                 
330                 if (session_removal_countdown > nframes) {
331                         session_removal_countdown -= nframes;
332                 } else {
333                         session_removal_countdown = 0;
334                 }
335
336                 session_removal_gain -= (nframes * session_removal_gain_step);
337         }
338
339         PortManager::cycle_end (nframes);
340
341         _processed_frames = next_processed_frames;
342
343         PT_TIMING_CHECK (2);
344         
345         return 0;
346 }
347
348
349 void
350 AudioEngine::stop_metering_thread ()
351 {
352         if (m_meter_thread) {
353                 g_atomic_int_set (&m_meter_exit, 1);
354                 m_meter_thread->join ();
355                 m_meter_thread = 0;
356         }
357 }
358
359 void
360 AudioEngine::start_metering_thread ()
361 {
362         if (m_meter_thread == 0) {
363                 g_atomic_int_set (&m_meter_exit, 0);
364                 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
365         }
366 }
367
368 void
369 AudioEngine::meter_thread ()
370 {
371         pthread_set_name (X_("meter"));
372
373         while (true) {
374                 Glib::usleep (10000); /* 1/100th sec interval */
375                 if (g_atomic_int_get(&m_meter_exit)) {
376                         break;
377                 }
378                 Metering::Meter ();
379         }
380 }
381
382 void
383 AudioEngine::set_session (Session *s)
384 {
385         Glib::Threads::Mutex::Lock pl (_process_lock);
386
387         SessionHandlePtr::set_session (s);
388
389         if (_session) {
390
391                 pframes_t blocksize = samples_per_cycle ();
392
393                 PortManager::cycle_start (blocksize);
394
395                 _session->process (blocksize);
396                 _session->process (blocksize);
397                 _session->process (blocksize);
398                 _session->process (blocksize);
399                 _session->process (blocksize);
400                 _session->process (blocksize);
401                 _session->process (blocksize);
402                 _session->process (blocksize);
403
404                 PortManager::cycle_end (blocksize);
405         }
406 }
407
408 void
409 AudioEngine::remove_session ()
410 {
411         Glib::Threads::Mutex::Lock lm (_process_lock);
412
413         if (_running) {
414
415                 stop_metering_thread ();
416
417                 if (_session) {
418                         session_remove_pending = true;
419                         session_removal_countdown = 0;
420                         session_removed.wait(_process_lock);
421                 }
422
423         } else {
424                 SessionHandlePtr::set_session (0);
425         }
426
427         remove_all_ports ();
428 }
429
430
431 void
432 AudioEngine::died ()
433 {
434         /* called from a signal handler for SIGPIPE */
435
436         stop_metering_thread ();
437
438         _running = false;
439 }
440
441 int
442 AudioEngine::reset_timebase ()
443 {
444         if (_session) {
445                 if (_session->config.get_jack_time_master()) {
446                         _backend->set_time_master (true);
447                 } else {
448                         _backend->set_time_master (false);
449                 }
450         }
451         return 0;
452 }
453
454
455 void
456 AudioEngine::destroy ()
457 {
458         delete _instance;
459         _instance = 0;
460 }
461
462 int
463 AudioEngine::discover_backends ()
464 {
465         vector<std::string> backend_modules;
466
467         _backends.clear ();
468
469         Glib::PatternSpec so_extension_pattern("*backend.so");
470         Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
471
472         find_matching_files_in_search_path (backend_search_path (),
473                                             so_extension_pattern, backend_modules);
474
475         find_matching_files_in_search_path (backend_search_path (),
476                                             dylib_extension_pattern, backend_modules);
477
478         DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1\n"), backend_search_path().to_string()));
479
480         for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
481
482                 AudioBackendInfo* info;
483
484                 if ((info = backend_discover (*i)) != 0) {
485                         _backends.insert (make_pair (info->name, info));
486                 }
487         }
488
489         return _backends.size();
490 }
491
492 AudioBackendInfo*
493 AudioEngine::backend_discover (const string& path)
494 {
495         Glib::Module module (path);
496         AudioBackendInfo* info;
497         void* sym = 0;
498
499         if (!module) {
500                 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
501                                         Glib::Module::get_last_error()) << endmsg;
502                 return 0;
503         }
504         
505         if (!module.get_symbol ("descriptor", sym)) {
506                 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor."), path) << endmsg;
507                 error << Glib::Module::get_last_error() << endmsg;
508                 return 0;
509         }
510
511         module.make_resident ();
512         
513         info = (AudioBackendInfo*) sym;
514         
515         return info;
516 }
517
518 vector<const AudioBackendInfo*>
519 AudioEngine::available_backends() const
520 {
521         vector<const AudioBackendInfo*> r;
522         
523         for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
524                 r.push_back (i->second);
525         }
526
527         return r;
528 }
529
530 string
531 AudioEngine::current_backend_name() const
532 {
533         if (_backend) {
534                 return _backend->name();
535         } 
536         return string();
537 }
538
539 void
540 AudioEngine::drop_backend ()
541 {
542         if (_backend) {
543                 _backend->stop ();
544                 _backend.reset ();
545         }
546 }
547
548 boost::shared_ptr<AudioBackend>
549 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
550 {
551         BackendMap::iterator b = _backends.find (name);
552
553         if (b == _backends.end()) {
554                 return boost::shared_ptr<AudioBackend>();
555         }
556
557         drop_backend ();
558         
559         try {
560                 if (b->second->instantiate (arg1, arg2)) {
561                         throw failed_constructor ();
562                 }
563
564                 _backend = b->second->backend_factory (*this);
565                 _impl = b->second->portengine_factory (*this);
566
567         } catch (exception& e) {
568                 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
569                 return boost::shared_ptr<AudioBackend>();
570         }
571
572         return _backend;
573 }
574
575 /* BACKEND PROXY WRAPPERS */
576
577 int
578 AudioEngine::start ()
579 {
580         if (!_backend) {
581                 return -1;
582         }
583
584         if (_running) {
585                 return 0;
586         }
587
588         _processed_frames = 0;
589         last_monitor_check = 0;
590         
591         if (_backend->start()) {
592                 return -1;
593         }
594
595         _running = true;
596         
597         if (_session) {
598                 _session->set_frame_rate (_backend->sample_rate());
599                 
600                 if (_session->config.get_jack_time_master()) {
601                         _backend->set_time_master (true);
602                 }
603         }
604         
605         start_metering_thread ();
606         
607         Running(); /* EMIT SIGNAL */
608         
609         return 0;
610 }
611
612 int
613 AudioEngine::stop ()
614 {
615         if (!_backend) {
616                 return 0;
617         }
618
619         Glib::Threads::Mutex::Lock lm (_process_lock);
620
621         if (_backend->stop ()) {
622                 return -1;
623         }
624         
625         _running = false;
626         _processed_frames = 0;
627         _measuring_latency = false;
628         _latency_output_port = 0;
629         _latency_input_port = 0;
630         stop_metering_thread ();
631         
632         Port::PortDrop ();
633         Stopped (); /* EMIT SIGNAL */
634         
635         return 0;
636 }
637
638 int
639 AudioEngine::pause ()
640 {
641         if (!_backend) {
642                 return 0;
643         }
644         
645         if (_backend->pause ()) {
646                 return -1;
647         }
648
649         _running = false;
650         
651         Stopped(); /* EMIT SIGNAL */
652         return 0;
653 }
654
655 int
656 AudioEngine::freewheel (bool start_stop)
657 {
658         if (!_backend) {
659                 return -1;
660         }
661
662         /* _freewheeling will be set when first Freewheel signal occurs */
663
664         return _backend->freewheel (start_stop);
665 }
666
667 float
668 AudioEngine::get_cpu_load() const 
669 {
670         if (!_backend) {
671                 return 0.0;
672         }
673         return _backend->cpu_load ();
674 }
675
676 bool
677 AudioEngine::is_realtime() const 
678 {
679         if (!_backend) {
680                 return false;
681         }
682
683         return _backend->is_realtime();
684 }
685
686 bool
687 AudioEngine::connected() const 
688 {
689         if (!_backend) {
690                 return false;
691         }
692
693         return _backend->connected();
694 }
695
696 void
697 AudioEngine::transport_start ()
698 {
699         if (!_backend) {
700                 return;
701         }
702         return _backend->transport_start ();
703 }
704
705 void
706 AudioEngine::transport_stop ()
707 {
708         if (!_backend) {
709                 return;
710         }
711         return _backend->transport_stop ();
712 }
713
714 TransportState
715 AudioEngine::transport_state ()
716 {
717         if (!_backend) {
718                 return TransportStopped;
719         }
720         return _backend->transport_state ();
721 }
722
723 void
724 AudioEngine::transport_locate (framepos_t pos)
725 {
726         if (!_backend) {
727                 return;
728         }
729         return _backend->transport_locate (pos);
730 }
731
732 framepos_t
733 AudioEngine::transport_frame()
734 {
735         if (!_backend) {
736                 return 0;
737         }
738         return _backend->transport_frame ();
739 }
740
741 framecnt_t
742 AudioEngine::sample_rate () const
743 {
744         if (!_backend) {
745                 return 0;
746         }
747         return _backend->sample_rate ();
748 }
749
750 pframes_t
751 AudioEngine::samples_per_cycle () const
752 {
753         if (!_backend) {
754                 return 0;
755         }
756         return _backend->buffer_size ();
757 }
758
759 int
760 AudioEngine::usecs_per_cycle () const
761 {
762         if (!_backend) {
763                 return -1;
764         }
765         return _backend->usecs_per_cycle ();
766 }
767
768 size_t
769 AudioEngine::raw_buffer_size (DataType t)
770 {
771         if (!_backend) {
772                 return -1;
773         }
774         return _backend->raw_buffer_size (t);
775 }
776
777 pframes_t
778 AudioEngine::sample_time ()
779 {
780         if (!_backend) {
781                 return 0;
782         }
783         return _backend->sample_time ();
784 }
785
786 pframes_t
787 AudioEngine::sample_time_at_cycle_start ()
788 {
789         if (!_backend) {
790                 return 0;
791         }
792         return _backend->sample_time_at_cycle_start ();
793 }
794
795 pframes_t
796 AudioEngine::samples_since_cycle_start ()
797 {
798         if (!_backend) {
799                 return 0;
800         }
801         return _backend->samples_since_cycle_start ();
802 }
803
804 bool
805 AudioEngine::get_sync_offset (pframes_t& offset) const
806 {
807         if (!_backend) {
808                 return false;
809         }
810         return _backend->get_sync_offset (offset);
811 }
812
813 int
814 AudioEngine::create_process_thread (boost::function<void()> func, pthread_t* thr, size_t stacksize)
815 {
816         if (!_backend) {
817                 return -1;
818         }
819         return _backend->create_process_thread (func, thr, stacksize);
820 }
821
822
823 int
824 AudioEngine::set_device_name (const std::string& name)
825 {
826         if (!_backend) {
827                 return -1;
828         }
829         return _backend->set_device_name  (name);
830 }
831
832 int
833 AudioEngine::set_sample_rate (float sr)
834 {
835         if (!_backend) {
836                 return -1;
837         }
838         return _backend->set_sample_rate  (sr);
839 }
840
841 int
842 AudioEngine::set_buffer_size (uint32_t bufsiz)
843 {
844         if (!_backend) {
845                 return -1;
846         }
847         return _backend->set_buffer_size  (bufsiz);
848 }
849
850 int
851 AudioEngine::set_sample_format (SampleFormat sf)
852 {
853         if (!_backend) {
854                 return -1;
855         }
856         return _backend->set_sample_format  (sf);
857 }
858
859 int
860 AudioEngine::set_interleaved (bool yn)
861 {
862         if (!_backend) {
863                 return -1;
864         }
865         return _backend->set_interleaved  (yn);
866 }
867
868 int
869 AudioEngine::set_input_channels (uint32_t ic)
870 {
871         if (!_backend) {
872                 return -1;
873         }
874         return _backend->set_input_channels  (ic);
875 }
876
877 int
878 AudioEngine::set_output_channels (uint32_t oc)
879 {
880         if (!_backend) {
881                 return -1;
882         }
883         return _backend->set_output_channels (oc);
884 }
885
886 int
887 AudioEngine::set_systemic_input_latency (uint32_t il)
888 {
889         if (!_backend) {
890                 return -1;
891         }
892         return _backend->set_systemic_input_latency  (il);
893 }
894
895 int
896 AudioEngine::set_systemic_output_latency (uint32_t ol)
897 {
898         if (!_backend) {
899                 return -1;
900         }
901         return _backend->set_systemic_output_latency  (ol);
902 }
903
904 /* END OF BACKEND PROXY API */
905
906 void
907 AudioEngine::thread_init_callback (void* arg)
908 {
909         /* make sure that anybody who needs to know about this thread
910            knows about it.
911         */
912
913         pthread_set_name (X_("audioengine"));
914
915         PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
916         PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
917
918         SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
919
920         AsyncMIDIPort::set_process_thread (pthread_self());
921
922         if (arg) {
923                 /* the special thread created/managed by the backend */
924                 AudioEngine::instance()->_main_thread = new ProcessThread;
925         }
926 }
927
928 int
929 AudioEngine::sync_callback (TransportState state, framepos_t position)
930 {
931         if (_session) {
932                 return _session->backend_sync_callback (state, position);
933         }
934         return 0;
935 }
936
937 void
938 AudioEngine::freewheel_callback (bool onoff)
939 {
940         _freewheeling = onoff;
941 }
942
943 void
944 AudioEngine::latency_callback (bool for_playback)
945 {
946         if (_session) {
947                 _session->update_latency (for_playback);
948         }
949 }
950
951 void
952 AudioEngine::update_latencies ()
953 {
954         if (_backend) {
955                 _backend->update_latencies ();
956         }
957 }
958
959 void
960 AudioEngine::halted_callback (const char* why)
961 {
962         stop_metering_thread ();
963         _running = false;
964
965         Port::PortDrop (); /* EMIT SIGNAL */
966         Halted (why);      /* EMIT SIGNAL */
967 }
968
969 bool
970 AudioEngine::setup_required () const
971 {
972         if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
973                 return false;
974         }
975
976         return true;
977 }
978
979 MTDM*
980 AudioEngine::mtdm() 
981 {
982         return _mtdm;
983 }
984
985 void
986 AudioEngine::start_latency_detection ()
987 {
988         PortEngine& pe (port_engine());
989
990         delete _mtdm;
991         _mtdm = 0;
992
993         /* create the ports we will use to read/write data */
994         
995         if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
996                 return;
997         }
998         if (pe.connect (_latency_output_port, _latency_output_name)) {
999                 return;
1000         }
1001
1002         const string portname ("latency_in");
1003         if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1004                 pe.unregister_port (_latency_output_port);
1005                 return;
1006         }
1007         if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1008                 pe.unregister_port (_latency_output_port);
1009                 return;
1010         }
1011         
1012         /* all created and connected, lets go */
1013
1014         _mtdm = new MTDM (sample_rate());
1015         _measuring_latency = true;
1016         _latency_flush_frames = samples_per_cycle();
1017
1018
1019 }
1020
1021 void
1022 AudioEngine::stop_latency_detection ()
1023 {
1024         port_engine().unregister_port (_latency_output_port);
1025         port_engine().unregister_port (_latency_input_port);
1026         _measuring_latency = false;
1027 }
1028
1029 void
1030 AudioEngine::set_latency_output_port (const string& name)
1031 {
1032         _latency_output_name = name;
1033 }
1034
1035 void
1036 AudioEngine::set_latency_input_port (const string& name)
1037 {
1038         _latency_input_name = name;
1039 }