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();
104 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
105 i->second->deinstantiate();
110 AudioEngine::create ()
116 _instance = new AudioEngine ();
122 AudioEngine::split_cycle (pframes_t offset)
124 /* caller must hold process lock */
126 Port::increment_global_port_buffer_offset (offset);
128 /* tell all Ports that we're going to start a new (split) cycle */
130 boost::shared_ptr<Ports> p = ports.reader();
132 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
133 i->second->cycle_split ();
138 AudioEngine::sample_rate_change (pframes_t nframes)
140 /* check for monitor input change every 1/10th of second */
142 monitor_check_interval = nframes / 10;
143 last_monitor_check = 0;
146 _session->set_frame_rate (nframes);
149 SampleRateChanged (nframes); /* EMIT SIGNAL */
155 AudioEngine::buffer_size_change (pframes_t bufsiz)
158 _session->set_block_size (bufsiz);
159 last_monitor_check = 0;
162 BufferSizeChanged (bufsiz); /* EMIT SIGNAL */
167 /** Method called by our ::process_thread when there is work to be done.
168 * @param nframes Number of frames to process.
171 __attribute__((annotate("realtime")))
174 AudioEngine::process_callback (pframes_t nframes)
176 Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
181 /// The number of frames that will have been processed when we've finished
182 pframes_t next_processed_frames;
184 /* handle wrap around of total frames counter */
186 if (max_framepos - _processed_frames < nframes) {
187 next_processed_frames = nframes - (max_framepos - _processed_frames);
189 next_processed_frames = _processed_frames + nframes;
193 /* return having done nothing */
194 _processed_frames = next_processed_frames;
198 bool return_after_remove_check = false;
200 if (_measuring_latency == MeasureAudio && _mtdm) {
201 /* run a normal cycle from the perspective of the PortManager
202 so that we get silence on all registered ports.
204 we overwrite the silence on the two ports used for latency
208 PortManager::cycle_start (nframes);
209 PortManager::silence (nframes);
211 if (_latency_input_port && _latency_output_port) {
212 PortEngine& pe (port_engine());
214 Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
215 Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
217 _mtdm->process (nframes, in, out);
220 PortManager::cycle_end (nframes);
221 return_after_remove_check = true;
223 } else if (_measuring_latency == MeasureMIDI && _mididm) {
224 /* run a normal cycle from the perspective of the PortManager
225 so that we get silence on all registered ports.
227 we overwrite the silence on the two ports used for latency
231 PortManager::cycle_start (nframes);
232 PortManager::silence (nframes);
234 if (_latency_input_port && _latency_output_port) {
235 PortEngine& pe (port_engine());
237 _mididm->process (nframes, pe,
238 pe.get_buffer (_latency_input_port, nframes),
239 pe.get_buffer (_latency_output_port, nframes));
242 PortManager::cycle_end (nframes);
243 return_after_remove_check = true;
245 } else if (_latency_flush_frames) {
247 /* wait for the appropriate duration for the MTDM signal to
248 * drain from the ports before we revert to normal behaviour.
251 PortManager::cycle_start (nframes);
252 PortManager::silence (nframes);
253 PortManager::cycle_end (nframes);
255 if (_latency_flush_frames > nframes) {
256 _latency_flush_frames -= nframes;
258 _latency_flush_frames = 0;
261 return_after_remove_check = true;
264 if (session_remove_pending) {
266 /* perform the actual session removal */
268 if (session_removal_countdown < 0) {
270 /* fade out over 1 second */
271 session_removal_countdown = sample_rate()/2;
272 session_removal_gain = 1.0;
273 session_removal_gain_step = 1.0/session_removal_countdown;
275 } else if (session_removal_countdown > 0) {
277 /* we'll be fading audio out.
279 if this is the last time we do this as part
280 of session removal, do a MIDI panic now
281 to get MIDI stopped. This relies on the fact
282 that "immediate data" (aka "out of band data") from
283 MIDI tracks is *appended* after any other data,
284 so that it emerges after any outbound note ons, etc.
287 if (session_removal_countdown <= nframes) {
288 _session->midi_panic ();
294 session_removal_countdown = -1; // reset to "not in progress"
295 session_remove_pending = false;
296 session_removed.signal(); // wakes up thread that initiated session removal
300 if (return_after_remove_check) {
306 if (!_freewheeling) {
307 PortManager::cycle_start (nframes);
308 PortManager::cycle_end (nframes);
311 _processed_frames = next_processed_frames;
316 /* tell all relevant objects that we're starting a new cycle */
318 InternalSend::CycleStart (nframes);
320 /* tell all Ports that we're starting a new cycle */
322 PortManager::cycle_start (nframes);
324 /* test if we are freewheeling and there are freewheel signals connected.
325 ardour should act normally even when freewheeling unless /it/ is
326 exporting (which is what Freewheel.empty() tests for).
329 if (_freewheeling && !Freewheel.empty()) {
332 _session->process (nframes);
340 _processed_frames = next_processed_frames;
344 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
346 PortManager::check_monitoring ();
347 last_monitor_check = next_processed_frames;
350 if (_session->silent()) {
351 PortManager::silence (nframes);
354 if (session_remove_pending && session_removal_countdown) {
356 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
358 if (session_removal_countdown > nframes) {
359 session_removal_countdown -= nframes;
361 session_removal_countdown = 0;
364 session_removal_gain -= (nframes * session_removal_gain_step);
367 PortManager::cycle_end (nframes);
369 _processed_frames = next_processed_frames;
378 AudioEngine::request_backend_reset()
380 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
381 g_atomic_int_inc (&_hw_reset_request_count);
382 _hw_reset_condition.signal ();
387 AudioEngine::do_reset_backend()
389 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
391 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
393 while (!_stop_hw_reset_processing) {
395 if (_hw_reset_request_count && _backend) {
397 _reset_request_lock.unlock();
399 Glib::Threads::RecMutex::Lock pl (_state_lock);
401 g_atomic_int_dec_and_test (&_hw_reset_request_count);
403 std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
405 // backup the device name
406 std::string name = _backend->device_name ();
408 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
411 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
412 if ( 0 == _backend->reset_device () ) {
414 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
417 // inform about possible changes
418 BufferSizeChanged (_backend->buffer_size() );
423 std::cout << "AudioEngine::RESET::Done." << std::endl;
425 _reset_request_lock.lock();
429 _hw_reset_condition.wait (_reset_request_lock);
437 AudioEngine::request_device_list_update()
439 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
440 g_atomic_int_inc (&_hw_devicelist_update_count);
441 _hw_devicelist_update_condition.signal ();
446 AudioEngine::do_devicelist_update()
448 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
450 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
452 while (!_stop_hw_devicelist_processing) {
454 if (_hw_devicelist_update_count) {
456 _devicelist_update_lock.unlock();
458 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
459 DeviceListChanged (); /* EMIT SIGNAL */
461 _devicelist_update_lock.lock();
464 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
471 AudioEngine::start_hw_event_processing()
473 if (_hw_reset_event_thread == 0) {
474 g_atomic_int_set(&_hw_reset_request_count, 0);
475 g_atomic_int_set(&_stop_hw_reset_processing, 0);
476 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
479 if (_hw_devicelist_update_thread == 0) {
480 g_atomic_int_set(&_hw_devicelist_update_count, 0);
481 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
482 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
488 AudioEngine::stop_hw_event_processing()
490 if (_hw_reset_event_thread) {
491 g_atomic_int_set(&_stop_hw_reset_processing, 1);
492 g_atomic_int_set(&_hw_reset_request_count, 0);
493 _hw_reset_condition.signal ();
494 _hw_reset_event_thread->join ();
495 _hw_reset_event_thread = 0;
498 if (_hw_devicelist_update_thread) {
499 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
500 g_atomic_int_set(&_hw_devicelist_update_count, 0);
501 _hw_devicelist_update_condition.signal ();
502 _hw_devicelist_update_thread->join ();
503 _hw_devicelist_update_thread = 0;
511 AudioEngine::stop_metering_thread ()
513 if (m_meter_thread) {
514 g_atomic_int_set (&m_meter_exit, 1);
515 m_meter_thread->join ();
521 AudioEngine::start_metering_thread ()
523 if (m_meter_thread == 0) {
524 g_atomic_int_set (&m_meter_exit, 0);
525 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
530 AudioEngine::meter_thread ()
532 pthread_set_name (X_("meter"));
535 Glib::usleep (10000); /* 1/100th sec interval */
536 if (g_atomic_int_get(&m_meter_exit)) {
544 AudioEngine::set_session (Session *s)
546 Glib::Threads::Mutex::Lock pl (_process_lock);
548 SessionHandlePtr::set_session (s);
552 pframes_t blocksize = samples_per_cycle ();
554 PortManager::cycle_start (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);
563 _session->process (blocksize);
565 PortManager::cycle_end (blocksize);
570 AudioEngine::remove_session ()
572 Glib::Threads::Mutex::Lock lm (_process_lock);
577 session_remove_pending = true;
578 session_removal_countdown = 0;
579 session_removed.wait(_process_lock);
583 SessionHandlePtr::set_session (0);
591 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
594 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
602 /* called from a signal handler for SIGPIPE */
604 stop_metering_thread ();
610 AudioEngine::reset_timebase ()
613 if (_session->config.get_jack_time_master()) {
614 _backend->set_time_master (true);
616 _backend->set_time_master (false);
624 AudioEngine::destroy ()
631 AudioEngine::discover_backends ()
633 vector<std::string> backend_modules;
637 Glib::PatternSpec so_extension_pattern("*backend.so");
638 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
640 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
641 #if defined(DEBUG) || defined(_DEBUG)
642 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
644 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
647 Glib::PatternSpec dll_extension_pattern("*backend.dll");
650 find_files_matching_pattern (backend_modules, backend_search_path (),
651 so_extension_pattern);
653 find_files_matching_pattern (backend_modules, backend_search_path (),
654 dylib_extension_pattern);
656 find_files_matching_pattern (backend_modules, backend_search_path (),
657 dll_extension_pattern);
659 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
661 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
663 AudioBackendInfo* info;
665 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
667 if ((info = backend_discover (*i)) != 0) {
668 _backends.insert (make_pair (info->name, info));
672 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
674 return _backends.size();
678 AudioEngine::backend_discover (const string& path)
680 #ifdef PLATFORM_WINDOWS
681 // do not show popup dialog (e.g. missing libjack.dll)
682 // win7+ should use SetThreadErrorMode()
683 SetErrorMode(SEM_FAILCRITICALERRORS);
685 Glib::Module module (path);
686 #ifdef PLATFORM_WINDOWS
687 SetErrorMode(0); // reset to system default
689 AudioBackendInfo* info;
690 AudioBackendInfo* (*dfunc)(void);
694 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
695 Glib::Module::get_last_error()) << endmsg;
699 if (!module.get_symbol ("descriptor", func)) {
700 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
701 error << Glib::Module::get_last_error() << endmsg;
705 dfunc = (AudioBackendInfo* (*)(void))func;
707 if (!info->available()) {
711 module.make_resident ();
716 vector<const AudioBackendInfo*>
717 AudioEngine::available_backends() const
719 vector<const AudioBackendInfo*> r;
721 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
722 r.push_back (i->second);
729 AudioEngine::current_backend_name() const
732 return _backend->name();
738 AudioEngine::drop_backend ()
742 _backend->drop_device ();
748 boost::shared_ptr<AudioBackend>
749 AudioEngine::set_default_backend ()
751 if (_backends.empty()) {
752 return boost::shared_ptr<AudioBackend>();
755 return set_backend (_backends.begin()->first, "", "");
758 boost::shared_ptr<AudioBackend>
759 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
761 BackendMap::iterator b = _backends.find (name);
763 if (b == _backends.end()) {
764 return boost::shared_ptr<AudioBackend>();
770 if (b->second->instantiate (arg1, arg2)) {
771 throw failed_constructor ();
774 _backend = b->second->factory (*this);
776 } catch (exception& e) {
777 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
778 return boost::shared_ptr<AudioBackend>();
784 /* BACKEND PROXY WRAPPERS */
787 AudioEngine::start (bool for_latency)
797 _processed_frames = 0;
798 last_monitor_check = 0;
800 if (_backend->start (for_latency)) {
807 _session->set_frame_rate (_backend->sample_rate());
809 if (_session->config.get_jack_time_master()) {
810 _backend->set_time_master (true);
815 start_metering_thread ();
818 Running(); /* EMIT SIGNAL */
825 AudioEngine::stop (bool for_latency)
831 if (_session && _running) {
832 // it's not a halt, but should be handled the same way:
833 // disable record, stop transport and I/O processign but save the data.
834 _session->engine_halted ();
837 Glib::Threads::Mutex::Lock lm (_process_lock);
839 if (_backend->stop ()) {
844 _processed_frames = 0;
845 _measuring_latency = MeasureNone;
846 _latency_output_port = 0;
847 _latency_input_port = 0;
848 _started_for_latency = false;
849 stop_metering_thread ();
854 Stopped (); /* EMIT SIGNAL */
861 AudioEngine::freewheel (bool start_stop)
867 /* _freewheeling will be set when first Freewheel signal occurs */
869 return _backend->freewheel (start_stop);
873 AudioEngine::get_dsp_load() const
878 return _backend->dsp_load ();
882 AudioEngine::is_realtime() const
888 return _backend->is_realtime();
892 AudioEngine::connected() const
898 return _backend->available();
902 AudioEngine::transport_start ()
907 return _backend->transport_start ();
911 AudioEngine::transport_stop ()
916 return _backend->transport_stop ();
920 AudioEngine::transport_state ()
923 return TransportStopped;
925 return _backend->transport_state ();
929 AudioEngine::transport_locate (framepos_t pos)
934 return _backend->transport_locate (pos);
938 AudioEngine::transport_frame()
943 return _backend->transport_frame ();
947 AudioEngine::sample_rate () const
952 return _backend->sample_rate ();
956 AudioEngine::samples_per_cycle () const
961 return _backend->buffer_size ();
965 AudioEngine::usecs_per_cycle () const
970 return _backend->usecs_per_cycle ();
974 AudioEngine::raw_buffer_size (DataType t)
979 return _backend->raw_buffer_size (t);
983 AudioEngine::sample_time ()
988 return _backend->sample_time ();
992 AudioEngine::sample_time_at_cycle_start ()
997 return _backend->sample_time_at_cycle_start ();
1001 AudioEngine::samples_since_cycle_start ()
1006 return _backend->samples_since_cycle_start ();
1010 AudioEngine::get_sync_offset (pframes_t& offset) const
1015 return _backend->get_sync_offset (offset);
1019 AudioEngine::create_process_thread (boost::function<void()> func)
1024 return _backend->create_process_thread (func);
1028 AudioEngine::join_process_threads ()
1033 return _backend->join_process_threads ();
1037 AudioEngine::in_process_thread ()
1042 return _backend->in_process_thread ();
1046 AudioEngine::process_thread_count ()
1051 return _backend->process_thread_count ();
1055 AudioEngine::set_device_name (const std::string& name)
1060 return _backend->set_device_name (name);
1064 AudioEngine::set_sample_rate (float sr)
1069 return _backend->set_sample_rate (sr);
1073 AudioEngine::set_buffer_size (uint32_t bufsiz)
1078 return _backend->set_buffer_size (bufsiz);
1082 AudioEngine::set_interleaved (bool yn)
1087 return _backend->set_interleaved (yn);
1091 AudioEngine::set_input_channels (uint32_t ic)
1096 return _backend->set_input_channels (ic);
1100 AudioEngine::set_output_channels (uint32_t oc)
1105 return _backend->set_output_channels (oc);
1109 AudioEngine::set_systemic_input_latency (uint32_t il)
1114 return _backend->set_systemic_input_latency (il);
1118 AudioEngine::set_systemic_output_latency (uint32_t ol)
1123 return _backend->set_systemic_output_latency (ol);
1126 /* END OF BACKEND PROXY API */
1129 AudioEngine::thread_init_callback (void* arg)
1131 /* make sure that anybody who needs to know about this thread
1135 pthread_set_name (X_("audioengine"));
1137 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1138 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1140 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1142 AsyncMIDIPort::set_process_thread (pthread_self());
1145 /* the special thread created/managed by the backend */
1146 AudioEngine::instance()->_main_thread = new ProcessThread;
1151 AudioEngine::sync_callback (TransportState state, framepos_t position)
1154 return _session->backend_sync_callback (state, position);
1160 AudioEngine::freewheel_callback (bool onoff)
1162 _freewheeling = onoff;
1166 AudioEngine::latency_callback (bool for_playback)
1169 _session->update_latency (for_playback);
1174 AudioEngine::update_latencies ()
1177 _backend->update_latencies ();
1182 AudioEngine::halted_callback (const char* why)
1184 if (_in_destructor) {
1185 /* everything is under control */
1189 stop_metering_thread ();
1192 Port::PortDrop (); /* EMIT SIGNAL */
1194 if (!_started_for_latency) {
1195 Halted (why); /* EMIT SIGNAL */
1200 AudioEngine::setup_required () const
1203 if (_backend->info().already_configured())
1206 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1215 AudioEngine::prepare_for_latency_measurement ()
1218 _stopped_for_latency = true;
1223 _started_for_latency = true;
1231 AudioEngine::start_latency_detection (bool for_midi)
1234 if (prepare_for_latency_measurement ()) {
1239 PortEngine& pe (port_engine());
1247 /* find the ports we will connect to */
1249 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1250 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1257 /* create the ports we will use to read/write data */
1259 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
1263 if (pe.connect (_latency_output_port, _latency_output_name)) {
1264 pe.unregister_port (_latency_output_port);
1269 const string portname ("latency_in");
1270 if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
1271 pe.unregister_port (_latency_input_port);
1272 pe.unregister_port (_latency_output_port);
1276 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1277 pe.unregister_port (_latency_input_port);
1278 pe.unregister_port (_latency_output_port);
1283 _mididm = new MIDIDM (sample_rate());
1287 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1291 if (pe.connect (_latency_output_port, _latency_output_name)) {
1292 pe.unregister_port (_latency_output_port);
1297 const string portname ("latency_in");
1298 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1299 pe.unregister_port (_latency_input_port);
1300 pe.unregister_port (_latency_output_port);
1304 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1305 pe.unregister_port (_latency_input_port);
1306 pe.unregister_port (_latency_output_port);
1311 _mtdm = new MTDM (sample_rate());
1316 _latency_signal_latency = 0;
1317 lr = pe.get_latency_range (in, false);
1318 _latency_signal_latency = lr.max;
1319 lr = pe.get_latency_range (out, true);
1320 _latency_signal_latency += lr.max;
1322 /* all created and connected, lets go */
1323 _latency_flush_frames = samples_per_cycle();
1324 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1330 AudioEngine::stop_latency_detection ()
1332 _measuring_latency = MeasureNone;
1334 if (_latency_output_port) {
1335 port_engine().unregister_port (_latency_output_port);
1336 _latency_output_port = 0;
1338 if (_latency_input_port) {
1339 port_engine().unregister_port (_latency_input_port);
1340 _latency_input_port = 0;
1345 if (_stopped_for_latency) {
1349 _stopped_for_latency = false;
1350 _started_for_latency = false;
1354 AudioEngine::set_latency_output_port (const string& name)
1356 _latency_output_name = name;
1360 AudioEngine::set_latency_input_port (const string& name)
1362 _latency_input_name = name;