2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <glibmm/timer.h>
28 #include <glibmm/pattern.h>
29 #include <glibmm/module.h>
32 #include "pbd/file_utils.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/stacktrace.h"
35 #include "pbd/unknown_type.h"
37 #include "midi++/port.h"
38 #include "midi++/mmc.h"
40 #include "ardour/async_midi_port.h"
41 #include "ardour/audio_port.h"
42 #include "ardour/audio_backend.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/search_paths.h"
45 #include "ardour/buffer.h"
46 #include "ardour/cycle_timer.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/meter.h"
49 #include "ardour/midi_port.h"
50 #include "ardour/midiport_manager.h"
51 #include "ardour/mididm.h"
52 #include "ardour/mtdm.h"
53 #include "ardour/port.h"
54 #include "ardour/process_thread.h"
55 #include "ardour/session.h"
60 using namespace ARDOUR;
63 gint AudioEngine::m_meter_exit;
64 AudioEngine* AudioEngine::_instance = 0;
66 AudioEngine::AudioEngine ()
67 : session_remove_pending (false)
68 , session_removal_countdown (-1)
70 , _freewheeling (false)
71 , monitor_check_interval (INT32_MAX)
72 , last_monitor_check (0)
73 , _processed_frames (0)
78 , _measuring_latency (MeasureNone)
79 , _latency_input_port (0)
80 , _latency_output_port (0)
81 , _latency_flush_frames (0)
82 , _latency_signal_latency (0)
83 , _stopped_for_latency (false)
84 , _started_for_latency (false)
85 , _in_destructor (false)
86 , _hw_reset_event_thread(0)
87 , _hw_reset_request_count(0)
88 , _stop_hw_reset_processing(0)
89 , _hw_devicelist_update_thread(0)
90 , _hw_devicelist_update_count(0)
91 , _stop_hw_devicelist_processing(0)
93 g_atomic_int_set (&m_meter_exit, 0);
94 start_hw_event_processing();
98 AudioEngine::~AudioEngine ()
100 _in_destructor = true;
101 stop_metering_thread ();
102 stop_hw_event_processing();
107 AudioEngine::create ()
113 _instance = new AudioEngine ();
119 AudioEngine::split_cycle (pframes_t offset)
121 /* caller must hold process lock */
123 Port::increment_global_port_buffer_offset (offset);
125 /* tell all Ports that we're going to start a new (split) cycle */
127 boost::shared_ptr<Ports> p = ports.reader();
129 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
130 i->second->cycle_split ();
135 AudioEngine::sample_rate_change (pframes_t nframes)
137 /* check for monitor input change every 1/10th of second */
139 monitor_check_interval = nframes / 10;
140 last_monitor_check = 0;
143 _session->set_frame_rate (nframes);
146 SampleRateChanged (nframes); /* EMIT SIGNAL */
152 AudioEngine::buffer_size_change (pframes_t bufsiz)
155 _session->set_block_size (bufsiz);
156 last_monitor_check = 0;
159 BufferSizeChanged (bufsiz); /* EMIT SIGNAL */
164 /** Method called by our ::process_thread when there is work to be done.
165 * @param nframes Number of frames to process.
168 __attribute__((annotate("realtime")))
171 AudioEngine::process_callback (pframes_t nframes)
173 Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
178 /// The number of frames that will have been processed when we've finished
179 pframes_t next_processed_frames;
181 /* handle wrap around of total frames counter */
183 if (max_framepos - _processed_frames < nframes) {
184 next_processed_frames = nframes - (max_framepos - _processed_frames);
186 next_processed_frames = _processed_frames + nframes;
190 /* return having done nothing */
191 _processed_frames = next_processed_frames;
195 bool return_after_remove_check = false;
197 if (_measuring_latency == MeasureAudio && _mtdm) {
198 /* run a normal cycle from the perspective of the PortManager
199 so that we get silence on all registered ports.
201 we overwrite the silence on the two ports used for latency
205 PortManager::cycle_start (nframes);
206 PortManager::silence (nframes);
208 if (_latency_input_port && _latency_output_port) {
209 PortEngine& pe (port_engine());
211 Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
212 Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
214 _mtdm->process (nframes, in, out);
217 PortManager::cycle_end (nframes);
218 return_after_remove_check = true;
220 } else if (_measuring_latency == MeasureMIDI && _mididm) {
221 /* run a normal cycle from the perspective of the PortManager
222 so that we get silence on all registered ports.
224 we overwrite the silence on the two ports used for latency
228 PortManager::cycle_start (nframes);
229 PortManager::silence (nframes);
231 if (_latency_input_port && _latency_output_port) {
232 PortEngine& pe (port_engine());
234 _mididm->process (nframes, pe,
235 pe.get_buffer (_latency_input_port, nframes),
236 pe.get_buffer (_latency_output_port, nframes));
239 PortManager::cycle_end (nframes);
240 return_after_remove_check = true;
242 } else if (_latency_flush_frames) {
244 /* wait for the appropriate duration for the MTDM signal to
245 * drain from the ports before we revert to normal behaviour.
248 PortManager::cycle_start (nframes);
249 PortManager::silence (nframes);
250 PortManager::cycle_end (nframes);
252 if (_latency_flush_frames > nframes) {
253 _latency_flush_frames -= nframes;
255 _latency_flush_frames = 0;
258 return_after_remove_check = true;
261 if (session_remove_pending) {
263 /* perform the actual session removal */
265 if (session_removal_countdown < 0) {
267 /* fade out over 1 second */
268 session_removal_countdown = sample_rate()/2;
269 session_removal_gain = 1.0;
270 session_removal_gain_step = 1.0/session_removal_countdown;
272 } else if (session_removal_countdown > 0) {
274 /* we'll be fading audio out.
276 if this is the last time we do this as part
277 of session removal, do a MIDI panic now
278 to get MIDI stopped. This relies on the fact
279 that "immediate data" (aka "out of band data") from
280 MIDI tracks is *appended* after any other data,
281 so that it emerges after any outbound note ons, etc.
284 if (session_removal_countdown <= nframes) {
285 _session->midi_panic ();
291 session_removal_countdown = -1; // reset to "not in progress"
292 session_remove_pending = false;
293 session_removed.signal(); // wakes up thread that initiated session removal
297 if (return_after_remove_check) {
303 if (!_freewheeling) {
304 PortManager::cycle_start (nframes);
305 PortManager::cycle_end (nframes);
308 _processed_frames = next_processed_frames;
313 /* tell all relevant objects that we're starting a new cycle */
315 InternalSend::CycleStart (nframes);
317 /* tell all Ports that we're starting a new cycle */
319 PortManager::cycle_start (nframes);
321 /* test if we are freewheeling and there are freewheel signals connected.
322 ardour should act normally even when freewheeling unless /it/ is
323 exporting (which is what Freewheel.empty() tests for).
326 if (_freewheeling && !Freewheel.empty()) {
329 _session->process (nframes);
337 _processed_frames = next_processed_frames;
341 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
343 PortManager::check_monitoring ();
344 last_monitor_check = next_processed_frames;
347 if (_session->silent()) {
348 PortManager::silence (nframes);
351 if (session_remove_pending && session_removal_countdown) {
353 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
355 if (session_removal_countdown > nframes) {
356 session_removal_countdown -= nframes;
358 session_removal_countdown = 0;
361 session_removal_gain -= (nframes * session_removal_gain_step);
364 PortManager::cycle_end (nframes);
366 _processed_frames = next_processed_frames;
375 AudioEngine::request_backend_reset()
377 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
378 g_atomic_int_inc (&_hw_reset_request_count);
379 _hw_reset_condition.signal ();
384 AudioEngine::do_reset_backend()
386 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
388 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
390 while (!_stop_hw_reset_processing) {
392 if (_hw_reset_request_count && _backend) {
394 _reset_request_lock.unlock();
396 Glib::Threads::RecMutex::Lock pl (_state_lock);
398 g_atomic_int_dec_and_test (&_hw_reset_request_count);
400 std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
402 // backup the device name
403 std::string name = _backend->device_name ();
405 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
408 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
409 if ( 0 == _backend->reset_device () ) {
411 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
414 // inform about possible changes
415 BufferSizeChanged (_backend->buffer_size() );
420 std::cout << "AudioEngine::RESET::Done." << std::endl;
422 _reset_request_lock.lock();
426 _hw_reset_condition.wait (_reset_request_lock);
434 AudioEngine::request_device_list_update()
436 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
437 g_atomic_int_inc (&_hw_devicelist_update_count);
438 _hw_devicelist_update_condition.signal ();
443 AudioEngine::do_devicelist_update()
445 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
447 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
449 while (!_stop_hw_devicelist_processing) {
451 if (_hw_devicelist_update_count) {
453 _devicelist_update_lock.unlock();
455 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
456 DeviceListChanged (); /* EMIT SIGNAL */
458 _devicelist_update_lock.lock();
461 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
468 AudioEngine::start_hw_event_processing()
470 if (_hw_reset_event_thread == 0) {
471 g_atomic_int_set(&_hw_reset_request_count, 0);
472 g_atomic_int_set(&_stop_hw_reset_processing, 0);
473 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
476 if (_hw_devicelist_update_thread == 0) {
477 g_atomic_int_set(&_hw_devicelist_update_count, 0);
478 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
479 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
485 AudioEngine::stop_hw_event_processing()
487 if (_hw_reset_event_thread) {
488 g_atomic_int_set(&_stop_hw_reset_processing, 1);
489 g_atomic_int_set(&_hw_reset_request_count, 0);
490 _hw_reset_condition.signal ();
491 _hw_reset_event_thread->join ();
492 _hw_reset_event_thread = 0;
495 if (_hw_devicelist_update_thread) {
496 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
497 g_atomic_int_set(&_hw_devicelist_update_count, 0);
498 _hw_devicelist_update_condition.signal ();
499 _hw_devicelist_update_thread->join ();
500 _hw_devicelist_update_thread = 0;
508 AudioEngine::stop_metering_thread ()
510 if (m_meter_thread) {
511 g_atomic_int_set (&m_meter_exit, 1);
512 m_meter_thread->join ();
518 AudioEngine::start_metering_thread ()
520 if (m_meter_thread == 0) {
521 g_atomic_int_set (&m_meter_exit, 0);
522 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
527 AudioEngine::meter_thread ()
529 pthread_set_name (X_("meter"));
532 Glib::usleep (10000); /* 1/100th sec interval */
533 if (g_atomic_int_get(&m_meter_exit)) {
541 AudioEngine::set_session (Session *s)
543 Glib::Threads::Mutex::Lock pl (_process_lock);
545 SessionHandlePtr::set_session (s);
549 pframes_t blocksize = samples_per_cycle ();
551 PortManager::cycle_start (blocksize);
553 _session->process (blocksize);
554 _session->process (blocksize);
555 _session->process (blocksize);
556 _session->process (blocksize);
557 _session->process (blocksize);
558 _session->process (blocksize);
559 _session->process (blocksize);
560 _session->process (blocksize);
562 PortManager::cycle_end (blocksize);
567 AudioEngine::remove_session ()
569 Glib::Threads::Mutex::Lock lm (_process_lock);
574 session_remove_pending = true;
575 session_removal_countdown = 0;
576 session_removed.wait(_process_lock);
580 SessionHandlePtr::set_session (0);
588 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
591 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
599 /* called from a signal handler for SIGPIPE */
601 stop_metering_thread ();
607 AudioEngine::reset_timebase ()
610 if (_session->config.get_jack_time_master()) {
611 _backend->set_time_master (true);
613 _backend->set_time_master (false);
621 AudioEngine::destroy ()
628 AudioEngine::discover_backends ()
630 vector<std::string> backend_modules;
634 Glib::PatternSpec so_extension_pattern("*backend.so");
635 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
637 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
638 #if defined(DEBUG) || defined(_DEBUG)
639 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
641 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
644 Glib::PatternSpec dll_extension_pattern("*backend.dll");
647 find_files_matching_pattern (backend_modules, backend_search_path (),
648 so_extension_pattern);
650 find_files_matching_pattern (backend_modules, backend_search_path (),
651 dylib_extension_pattern);
653 find_files_matching_pattern (backend_modules, backend_search_path (),
654 dll_extension_pattern);
656 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
658 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
660 AudioBackendInfo* info;
662 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
664 if ((info = backend_discover (*i)) != 0) {
665 _backends.insert (make_pair (info->name, info));
669 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
671 return _backends.size();
675 AudioEngine::backend_discover (const string& path)
677 #ifdef PLATFORM_WINDOWS
678 // do not show popup dialog (e.g. missing libjack.dll)
679 // win7+ should use SetThreadErrorMode()
680 SetErrorMode(SEM_FAILCRITICALERRORS);
682 Glib::Module module (path);
683 #ifdef PLATFORM_WINDOWS
684 SetErrorMode(0); // reset to system default
686 AudioBackendInfo* info;
687 AudioBackendInfo* (*dfunc)(void);
691 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
692 Glib::Module::get_last_error()) << endmsg;
696 if (!module.get_symbol ("descriptor", func)) {
697 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
698 error << Glib::Module::get_last_error() << endmsg;
702 dfunc = (AudioBackendInfo* (*)(void))func;
704 if (!info->available()) {
708 module.make_resident ();
713 vector<const AudioBackendInfo*>
714 AudioEngine::available_backends() const
716 vector<const AudioBackendInfo*> r;
718 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
719 r.push_back (i->second);
726 AudioEngine::current_backend_name() const
729 return _backend->name();
735 AudioEngine::drop_backend ()
739 _backend->drop_device ();
745 boost::shared_ptr<AudioBackend>
746 AudioEngine::set_default_backend ()
748 if (_backends.empty()) {
749 return boost::shared_ptr<AudioBackend>();
752 return set_backend (_backends.begin()->first, "", "");
755 boost::shared_ptr<AudioBackend>
756 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
758 BackendMap::iterator b = _backends.find (name);
760 if (b == _backends.end()) {
761 return boost::shared_ptr<AudioBackend>();
767 if (b->second->instantiate (arg1, arg2)) {
768 throw failed_constructor ();
771 _backend = b->second->factory (*this);
773 } catch (exception& e) {
774 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
775 return boost::shared_ptr<AudioBackend>();
781 /* BACKEND PROXY WRAPPERS */
784 AudioEngine::start (bool for_latency)
794 _processed_frames = 0;
795 last_monitor_check = 0;
797 if (_backend->start (for_latency)) {
804 _session->set_frame_rate (_backend->sample_rate());
806 if (_session->config.get_jack_time_master()) {
807 _backend->set_time_master (true);
812 start_metering_thread ();
815 Running(); /* EMIT SIGNAL */
822 AudioEngine::stop (bool for_latency)
828 if (_session && _running) {
829 // it's not a halt, but should be handled the same way:
830 // disable record, stop transport and I/O processign but save the data.
831 _session->engine_halted ();
834 Glib::Threads::Mutex::Lock lm (_process_lock);
836 if (_backend->stop ()) {
841 _processed_frames = 0;
842 _measuring_latency = MeasureNone;
843 _latency_output_port = 0;
844 _latency_input_port = 0;
845 _started_for_latency = false;
846 stop_metering_thread ();
851 Stopped (); /* EMIT SIGNAL */
858 AudioEngine::freewheel (bool start_stop)
864 /* _freewheeling will be set when first Freewheel signal occurs */
866 return _backend->freewheel (start_stop);
870 AudioEngine::get_dsp_load() const
875 return _backend->dsp_load ();
879 AudioEngine::is_realtime() const
885 return _backend->is_realtime();
889 AudioEngine::connected() const
895 return _backend->available();
899 AudioEngine::transport_start ()
904 return _backend->transport_start ();
908 AudioEngine::transport_stop ()
913 return _backend->transport_stop ();
917 AudioEngine::transport_state ()
920 return TransportStopped;
922 return _backend->transport_state ();
926 AudioEngine::transport_locate (framepos_t pos)
931 return _backend->transport_locate (pos);
935 AudioEngine::transport_frame()
940 return _backend->transport_frame ();
944 AudioEngine::sample_rate () const
949 return _backend->sample_rate ();
953 AudioEngine::samples_per_cycle () const
958 return _backend->buffer_size ();
962 AudioEngine::usecs_per_cycle () const
967 return _backend->usecs_per_cycle ();
971 AudioEngine::raw_buffer_size (DataType t)
976 return _backend->raw_buffer_size (t);
980 AudioEngine::sample_time ()
985 return _backend->sample_time ();
989 AudioEngine::sample_time_at_cycle_start ()
994 return _backend->sample_time_at_cycle_start ();
998 AudioEngine::samples_since_cycle_start ()
1003 return _backend->samples_since_cycle_start ();
1007 AudioEngine::get_sync_offset (pframes_t& offset) const
1012 return _backend->get_sync_offset (offset);
1016 AudioEngine::create_process_thread (boost::function<void()> func)
1021 return _backend->create_process_thread (func);
1025 AudioEngine::join_process_threads ()
1030 return _backend->join_process_threads ();
1034 AudioEngine::in_process_thread ()
1039 return _backend->in_process_thread ();
1043 AudioEngine::process_thread_count ()
1048 return _backend->process_thread_count ();
1052 AudioEngine::set_device_name (const std::string& name)
1057 return _backend->set_device_name (name);
1061 AudioEngine::set_sample_rate (float sr)
1066 return _backend->set_sample_rate (sr);
1070 AudioEngine::set_buffer_size (uint32_t bufsiz)
1075 return _backend->set_buffer_size (bufsiz);
1079 AudioEngine::set_interleaved (bool yn)
1084 return _backend->set_interleaved (yn);
1088 AudioEngine::set_input_channels (uint32_t ic)
1093 return _backend->set_input_channels (ic);
1097 AudioEngine::set_output_channels (uint32_t oc)
1102 return _backend->set_output_channels (oc);
1106 AudioEngine::set_systemic_input_latency (uint32_t il)
1111 return _backend->set_systemic_input_latency (il);
1115 AudioEngine::set_systemic_output_latency (uint32_t ol)
1120 return _backend->set_systemic_output_latency (ol);
1123 /* END OF BACKEND PROXY API */
1126 AudioEngine::thread_init_callback (void* arg)
1128 /* make sure that anybody who needs to know about this thread
1132 pthread_set_name (X_("audioengine"));
1134 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1135 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1137 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1139 AsyncMIDIPort::set_process_thread (pthread_self());
1142 /* the special thread created/managed by the backend */
1143 AudioEngine::instance()->_main_thread = new ProcessThread;
1148 AudioEngine::sync_callback (TransportState state, framepos_t position)
1151 return _session->backend_sync_callback (state, position);
1157 AudioEngine::freewheel_callback (bool onoff)
1159 _freewheeling = onoff;
1163 AudioEngine::latency_callback (bool for_playback)
1166 _session->update_latency (for_playback);
1171 AudioEngine::update_latencies ()
1174 _backend->update_latencies ();
1179 AudioEngine::halted_callback (const char* why)
1181 if (_in_destructor) {
1182 /* everything is under control */
1186 stop_metering_thread ();
1189 Port::PortDrop (); /* EMIT SIGNAL */
1191 if (!_started_for_latency) {
1192 Halted (why); /* EMIT SIGNAL */
1197 AudioEngine::setup_required () const
1200 if (_backend->info().already_configured())
1203 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1212 AudioEngine::prepare_for_latency_measurement ()
1215 _stopped_for_latency = true;
1220 _started_for_latency = true;
1228 AudioEngine::start_latency_detection (bool for_midi)
1231 if (prepare_for_latency_measurement ()) {
1236 PortEngine& pe (port_engine());
1244 /* find the ports we will connect to */
1246 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1247 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1254 /* create the ports we will use to read/write data */
1256 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
1260 if (pe.connect (_latency_output_port, _latency_output_name)) {
1261 pe.unregister_port (_latency_output_port);
1266 const string portname ("latency_in");
1267 if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
1268 pe.unregister_port (_latency_input_port);
1269 pe.unregister_port (_latency_output_port);
1273 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1274 pe.unregister_port (_latency_input_port);
1275 pe.unregister_port (_latency_output_port);
1280 _mididm = new MIDIDM (sample_rate());
1284 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1288 if (pe.connect (_latency_output_port, _latency_output_name)) {
1289 pe.unregister_port (_latency_output_port);
1294 const string portname ("latency_in");
1295 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1296 pe.unregister_port (_latency_input_port);
1297 pe.unregister_port (_latency_output_port);
1301 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1302 pe.unregister_port (_latency_input_port);
1303 pe.unregister_port (_latency_output_port);
1308 _mtdm = new MTDM (sample_rate());
1313 _latency_signal_latency = 0;
1314 lr = pe.get_latency_range (in, false);
1315 _latency_signal_latency = lr.max;
1316 lr = pe.get_latency_range (out, true);
1317 _latency_signal_latency += lr.max;
1319 /* all created and connected, lets go */
1320 _latency_flush_frames = samples_per_cycle();
1321 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1327 AudioEngine::stop_latency_detection ()
1329 _measuring_latency = MeasureNone;
1331 if (_latency_output_port) {
1332 port_engine().unregister_port (_latency_output_port);
1333 _latency_output_port = 0;
1335 if (_latency_input_port) {
1336 port_engine().unregister_port (_latency_input_port);
1337 _latency_input_port = 0;
1342 if (_stopped_for_latency) {
1346 _stopped_for_latency = false;
1347 _started_for_latency = false;
1351 AudioEngine::set_latency_output_port (const string& name)
1353 _latency_output_name = name;
1357 AudioEngine::set_latency_input_port (const string& name)
1359 _latency_input_name = name;