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()) {
330 _session->process (nframes);
339 _processed_frames = next_processed_frames;
343 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
345 PortManager::check_monitoring ();
346 last_monitor_check = next_processed_frames;
349 if (_session->silent()) {
350 PortManager::silence (nframes);
353 if (session_remove_pending && session_removal_countdown) {
355 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
357 if (session_removal_countdown > nframes) {
358 session_removal_countdown -= nframes;
360 session_removal_countdown = 0;
363 session_removal_gain -= (nframes * session_removal_gain_step);
366 PortManager::cycle_end (nframes);
368 _processed_frames = next_processed_frames;
377 AudioEngine::request_backend_reset()
379 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
380 g_atomic_int_inc (&_hw_reset_request_count);
381 _hw_reset_condition.signal ();
386 AudioEngine::do_reset_backend()
388 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
390 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
392 while (!_stop_hw_reset_processing) {
394 if (_hw_reset_request_count && _backend) {
396 _reset_request_lock.unlock();
398 Glib::Threads::RecMutex::Lock pl (_state_lock);
400 g_atomic_int_dec_and_test (&_hw_reset_request_count);
402 std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
404 // backup the device name
405 std::string name = _backend->device_name ();
407 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
410 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
411 if ( 0 == _backend->reset_device () ) {
413 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
416 // inform about possible changes
417 BufferSizeChanged (_backend->buffer_size() );
422 std::cout << "AudioEngine::RESET::Done." << std::endl;
424 _reset_request_lock.lock();
428 _hw_reset_condition.wait (_reset_request_lock);
436 AudioEngine::request_device_list_update()
438 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
439 g_atomic_int_inc (&_hw_devicelist_update_count);
440 _hw_devicelist_update_condition.signal ();
445 AudioEngine::do_devicelist_update()
447 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
449 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
451 while (!_stop_hw_devicelist_processing) {
453 if (_hw_devicelist_update_count) {
455 _devicelist_update_lock.unlock();
457 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
458 DeviceListChanged (); /* EMIT SIGNAL */
460 _devicelist_update_lock.lock();
463 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
470 AudioEngine::start_hw_event_processing()
472 if (_hw_reset_event_thread == 0) {
473 g_atomic_int_set(&_hw_reset_request_count, 0);
474 g_atomic_int_set(&_stop_hw_reset_processing, 0);
475 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
478 if (_hw_devicelist_update_thread == 0) {
479 g_atomic_int_set(&_hw_devicelist_update_count, 0);
480 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
481 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
487 AudioEngine::stop_hw_event_processing()
489 if (_hw_reset_event_thread) {
490 g_atomic_int_set(&_stop_hw_reset_processing, 1);
491 g_atomic_int_set(&_hw_reset_request_count, 0);
492 _hw_reset_condition.signal ();
493 _hw_reset_event_thread->join ();
494 _hw_reset_event_thread = 0;
497 if (_hw_devicelist_update_thread) {
498 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
499 g_atomic_int_set(&_hw_devicelist_update_count, 0);
500 _hw_devicelist_update_condition.signal ();
501 _hw_devicelist_update_thread->join ();
502 _hw_devicelist_update_thread = 0;
510 AudioEngine::stop_metering_thread ()
512 if (m_meter_thread) {
513 g_atomic_int_set (&m_meter_exit, 1);
514 m_meter_thread->join ();
520 AudioEngine::start_metering_thread ()
522 if (m_meter_thread == 0) {
523 g_atomic_int_set (&m_meter_exit, 0);
524 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
529 AudioEngine::meter_thread ()
531 pthread_set_name (X_("meter"));
534 Glib::usleep (10000); /* 1/100th sec interval */
535 if (g_atomic_int_get(&m_meter_exit)) {
543 AudioEngine::set_session (Session *s)
545 Glib::Threads::Mutex::Lock pl (_process_lock);
547 SessionHandlePtr::set_session (s);
551 pframes_t blocksize = samples_per_cycle ();
553 PortManager::cycle_start (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);
561 _session->process (blocksize);
562 _session->process (blocksize);
564 PortManager::cycle_end (blocksize);
569 AudioEngine::remove_session ()
571 Glib::Threads::Mutex::Lock lm (_process_lock);
576 session_remove_pending = true;
577 session_removal_countdown = 0;
578 session_removed.wait(_process_lock);
582 SessionHandlePtr::set_session (0);
590 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
593 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
601 /* called from a signal handler for SIGPIPE */
603 stop_metering_thread ();
609 AudioEngine::reset_timebase ()
612 if (_session->config.get_jack_time_master()) {
613 _backend->set_time_master (true);
615 _backend->set_time_master (false);
623 AudioEngine::destroy ()
630 AudioEngine::discover_backends ()
632 vector<std::string> backend_modules;
636 Glib::PatternSpec so_extension_pattern("*backend.so");
637 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
639 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
640 #if defined(DEBUG) || defined(_DEBUG)
641 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
643 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
646 Glib::PatternSpec dll_extension_pattern("*backend.dll");
649 find_files_matching_pattern (backend_modules, backend_search_path (),
650 so_extension_pattern);
652 find_files_matching_pattern (backend_modules, backend_search_path (),
653 dylib_extension_pattern);
655 find_files_matching_pattern (backend_modules, backend_search_path (),
656 dll_extension_pattern);
658 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
660 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
662 AudioBackendInfo* info;
664 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
666 if ((info = backend_discover (*i)) != 0) {
667 _backends.insert (make_pair (info->name, info));
671 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
673 return _backends.size();
677 AudioEngine::backend_discover (const string& path)
679 #ifdef PLATFORM_WINDOWS
680 // do not show popup dialog (e.g. missing libjack.dll)
681 // win7+ should use SetThreadErrorMode()
682 SetErrorMode(SEM_FAILCRITICALERRORS);
684 Glib::Module module (path);
685 #ifdef PLATFORM_WINDOWS
686 SetErrorMode(0); // reset to system default
688 AudioBackendInfo* info;
689 AudioBackendInfo* (*dfunc)(void);
693 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
694 Glib::Module::get_last_error()) << endmsg;
698 if (!module.get_symbol ("descriptor", func)) {
699 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
700 error << Glib::Module::get_last_error() << endmsg;
704 dfunc = (AudioBackendInfo* (*)(void))func;
706 if (!info->available()) {
710 module.make_resident ();
715 vector<const AudioBackendInfo*>
716 AudioEngine::available_backends() const
718 vector<const AudioBackendInfo*> r;
720 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
721 r.push_back (i->second);
728 AudioEngine::current_backend_name() const
731 return _backend->name();
737 AudioEngine::drop_backend ()
741 _backend->drop_device ();
747 boost::shared_ptr<AudioBackend>
748 AudioEngine::set_default_backend ()
750 if (_backends.empty()) {
751 return boost::shared_ptr<AudioBackend>();
754 return set_backend (_backends.begin()->first, "", "");
757 boost::shared_ptr<AudioBackend>
758 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
760 BackendMap::iterator b = _backends.find (name);
762 if (b == _backends.end()) {
763 return boost::shared_ptr<AudioBackend>();
769 if (b->second->instantiate (arg1, arg2)) {
770 throw failed_constructor ();
773 _backend = b->second->factory (*this);
775 } catch (exception& e) {
776 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
777 return boost::shared_ptr<AudioBackend>();
783 /* BACKEND PROXY WRAPPERS */
786 AudioEngine::start (bool for_latency)
796 _processed_frames = 0;
797 last_monitor_check = 0;
799 if (_backend->start (for_latency)) {
806 _session->set_frame_rate (_backend->sample_rate());
808 if (_session->config.get_jack_time_master()) {
809 _backend->set_time_master (true);
814 start_metering_thread ();
817 Running(); /* EMIT SIGNAL */
824 AudioEngine::stop (bool for_latency)
830 if (_session && _running) {
831 // it's not a halt, but should be handled the same way:
832 // disable record, stop transport and I/O processign but save the data.
833 _session->engine_halted ();
836 Glib::Threads::Mutex::Lock lm (_process_lock);
838 if (_backend->stop ()) {
843 _processed_frames = 0;
844 _measuring_latency = MeasureNone;
845 _latency_output_port = 0;
846 _latency_input_port = 0;
847 _started_for_latency = false;
848 stop_metering_thread ();
853 Stopped (); /* EMIT SIGNAL */
860 AudioEngine::freewheel (bool start_stop)
866 /* _freewheeling will be set when first Freewheel signal occurs */
868 return _backend->freewheel (start_stop);
872 AudioEngine::get_dsp_load() const
877 return _backend->dsp_load ();
881 AudioEngine::is_realtime() const
887 return _backend->is_realtime();
891 AudioEngine::connected() const
897 return _backend->available();
901 AudioEngine::transport_start ()
906 return _backend->transport_start ();
910 AudioEngine::transport_stop ()
915 return _backend->transport_stop ();
919 AudioEngine::transport_state ()
922 return TransportStopped;
924 return _backend->transport_state ();
928 AudioEngine::transport_locate (framepos_t pos)
933 return _backend->transport_locate (pos);
937 AudioEngine::transport_frame()
942 return _backend->transport_frame ();
946 AudioEngine::sample_rate () const
951 return _backend->sample_rate ();
955 AudioEngine::samples_per_cycle () const
960 return _backend->buffer_size ();
964 AudioEngine::usecs_per_cycle () const
969 return _backend->usecs_per_cycle ();
973 AudioEngine::raw_buffer_size (DataType t)
978 return _backend->raw_buffer_size (t);
982 AudioEngine::sample_time ()
987 return _backend->sample_time ();
991 AudioEngine::sample_time_at_cycle_start ()
996 return _backend->sample_time_at_cycle_start ();
1000 AudioEngine::samples_since_cycle_start ()
1005 return _backend->samples_since_cycle_start ();
1009 AudioEngine::get_sync_offset (pframes_t& offset) const
1014 return _backend->get_sync_offset (offset);
1018 AudioEngine::create_process_thread (boost::function<void()> func)
1023 return _backend->create_process_thread (func);
1027 AudioEngine::join_process_threads ()
1032 return _backend->join_process_threads ();
1036 AudioEngine::in_process_thread ()
1041 return _backend->in_process_thread ();
1045 AudioEngine::process_thread_count ()
1050 return _backend->process_thread_count ();
1054 AudioEngine::set_device_name (const std::string& name)
1059 return _backend->set_device_name (name);
1063 AudioEngine::set_sample_rate (float sr)
1068 return _backend->set_sample_rate (sr);
1072 AudioEngine::set_buffer_size (uint32_t bufsiz)
1077 return _backend->set_buffer_size (bufsiz);
1081 AudioEngine::set_interleaved (bool yn)
1086 return _backend->set_interleaved (yn);
1090 AudioEngine::set_input_channels (uint32_t ic)
1095 return _backend->set_input_channels (ic);
1099 AudioEngine::set_output_channels (uint32_t oc)
1104 return _backend->set_output_channels (oc);
1108 AudioEngine::set_systemic_input_latency (uint32_t il)
1113 return _backend->set_systemic_input_latency (il);
1117 AudioEngine::set_systemic_output_latency (uint32_t ol)
1122 return _backend->set_systemic_output_latency (ol);
1125 /* END OF BACKEND PROXY API */
1128 AudioEngine::thread_init_callback (void* arg)
1130 /* make sure that anybody who needs to know about this thread
1134 pthread_set_name (X_("audioengine"));
1136 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1137 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1139 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1141 AsyncMIDIPort::set_process_thread (pthread_self());
1144 /* the special thread created/managed by the backend */
1145 AudioEngine::instance()->_main_thread = new ProcessThread;
1150 AudioEngine::sync_callback (TransportState state, framepos_t position)
1153 return _session->backend_sync_callback (state, position);
1159 AudioEngine::freewheel_callback (bool onoff)
1161 _freewheeling = onoff;
1165 AudioEngine::latency_callback (bool for_playback)
1168 _session->update_latency (for_playback);
1173 AudioEngine::update_latencies ()
1176 _backend->update_latencies ();
1181 AudioEngine::halted_callback (const char* why)
1183 if (_in_destructor) {
1184 /* everything is under control */
1188 stop_metering_thread ();
1191 Port::PortDrop (); /* EMIT SIGNAL */
1193 if (!_started_for_latency) {
1194 Halted (why); /* EMIT SIGNAL */
1199 AudioEngine::setup_required () const
1202 if (_backend->info().already_configured())
1205 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1214 AudioEngine::prepare_for_latency_measurement ()
1217 _stopped_for_latency = true;
1222 _started_for_latency = true;
1230 AudioEngine::start_latency_detection (bool for_midi)
1233 if (prepare_for_latency_measurement ()) {
1238 PortEngine& pe (port_engine());
1246 /* find the ports we will connect to */
1248 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1249 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1256 /* create the ports we will use to read/write data */
1258 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
1262 if (pe.connect (_latency_output_port, _latency_output_name)) {
1263 pe.unregister_port (_latency_output_port);
1268 const string portname ("latency_in");
1269 if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
1270 pe.unregister_port (_latency_input_port);
1271 pe.unregister_port (_latency_output_port);
1275 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1276 pe.unregister_port (_latency_input_port);
1277 pe.unregister_port (_latency_output_port);
1282 _mididm = new MIDIDM (sample_rate());
1286 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1290 if (pe.connect (_latency_output_port, _latency_output_name)) {
1291 pe.unregister_port (_latency_output_port);
1296 const string portname ("latency_in");
1297 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1298 pe.unregister_port (_latency_input_port);
1299 pe.unregister_port (_latency_output_port);
1303 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1304 pe.unregister_port (_latency_input_port);
1305 pe.unregister_port (_latency_output_port);
1310 _mtdm = new MTDM (sample_rate());
1315 _latency_signal_latency = 0;
1316 lr = pe.get_latency_range (in, false);
1317 _latency_signal_latency = lr.max;
1318 lr = pe.get_latency_range (out, true);
1319 _latency_signal_latency += lr.max;
1321 /* all created and connected, lets go */
1322 _latency_flush_frames = samples_per_cycle();
1323 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1329 AudioEngine::stop_latency_detection ()
1331 _measuring_latency = MeasureNone;
1333 if (_latency_output_port) {
1334 port_engine().unregister_port (_latency_output_port);
1335 _latency_output_port = 0;
1337 if (_latency_input_port) {
1338 port_engine().unregister_port (_latency_input_port);
1339 _latency_input_port = 0;
1344 if (_stopped_for_latency) {
1348 _stopped_for_latency = false;
1349 _started_for_latency = false;
1353 AudioEngine::set_latency_output_port (const string& name)
1355 _latency_output_name = name;
1359 AudioEngine::set_latency_input_port (const string& name)
1361 _latency_input_name = name;