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