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);
336 PortManager::cycle_end (nframes);
341 PortManager::cycle_end (nframes);
342 _processed_frames = next_processed_frames;
346 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
348 PortManager::check_monitoring ();
349 last_monitor_check = next_processed_frames;
352 if (_session->silent()) {
353 PortManager::silence (nframes);
356 if (session_remove_pending && session_removal_countdown) {
358 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
360 if (session_removal_countdown > nframes) {
361 session_removal_countdown -= nframes;
363 session_removal_countdown = 0;
366 session_removal_gain -= (nframes * session_removal_gain_step);
369 PortManager::cycle_end (nframes);
371 _processed_frames = next_processed_frames;
380 AudioEngine::request_backend_reset()
382 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
383 g_atomic_int_inc (&_hw_reset_request_count);
384 _hw_reset_condition.signal ();
389 AudioEngine::do_reset_backend()
391 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
393 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
395 while (!_stop_hw_reset_processing) {
397 if (_hw_reset_request_count && _backend) {
399 _reset_request_lock.unlock();
401 Glib::Threads::RecMutex::Lock pl (_state_lock);
403 g_atomic_int_dec_and_test (&_hw_reset_request_count);
405 std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
407 // backup the device name
408 std::string name = _backend->device_name ();
410 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
413 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
414 if ( 0 == _backend->reset_device () ) {
416 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
419 // inform about possible changes
420 BufferSizeChanged (_backend->buffer_size() );
425 std::cout << "AudioEngine::RESET::Done." << std::endl;
427 _reset_request_lock.lock();
431 _hw_reset_condition.wait (_reset_request_lock);
439 AudioEngine::request_device_list_update()
441 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
442 g_atomic_int_inc (&_hw_devicelist_update_count);
443 _hw_devicelist_update_condition.signal ();
448 AudioEngine::do_devicelist_update()
450 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
452 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
454 while (!_stop_hw_devicelist_processing) {
456 if (_hw_devicelist_update_count) {
458 _devicelist_update_lock.unlock();
460 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
461 DeviceListChanged (); /* EMIT SIGNAL */
463 _devicelist_update_lock.lock();
466 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
473 AudioEngine::start_hw_event_processing()
475 if (_hw_reset_event_thread == 0) {
476 g_atomic_int_set(&_hw_reset_request_count, 0);
477 g_atomic_int_set(&_stop_hw_reset_processing, 0);
478 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
481 if (_hw_devicelist_update_thread == 0) {
482 g_atomic_int_set(&_hw_devicelist_update_count, 0);
483 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
484 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
490 AudioEngine::stop_hw_event_processing()
492 if (_hw_reset_event_thread) {
493 g_atomic_int_set(&_stop_hw_reset_processing, 1);
494 g_atomic_int_set(&_hw_reset_request_count, 0);
495 _hw_reset_condition.signal ();
496 _hw_reset_event_thread->join ();
497 _hw_reset_event_thread = 0;
500 if (_hw_devicelist_update_thread) {
501 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
502 g_atomic_int_set(&_hw_devicelist_update_count, 0);
503 _hw_devicelist_update_condition.signal ();
504 _hw_devicelist_update_thread->join ();
505 _hw_devicelist_update_thread = 0;
513 AudioEngine::stop_metering_thread ()
515 if (m_meter_thread) {
516 g_atomic_int_set (&m_meter_exit, 1);
517 m_meter_thread->join ();
523 AudioEngine::start_metering_thread ()
525 if (m_meter_thread == 0) {
526 g_atomic_int_set (&m_meter_exit, 0);
527 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
532 AudioEngine::meter_thread ()
534 pthread_set_name (X_("meter"));
537 Glib::usleep (10000); /* 1/100th sec interval */
538 if (g_atomic_int_get(&m_meter_exit)) {
546 AudioEngine::set_session (Session *s)
548 Glib::Threads::Mutex::Lock pl (_process_lock);
550 SessionHandlePtr::set_session (s);
554 pframes_t blocksize = samples_per_cycle ();
556 PortManager::cycle_start (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);
564 _session->process (blocksize);
565 _session->process (blocksize);
567 PortManager::cycle_end (blocksize);
572 AudioEngine::remove_session ()
574 Glib::Threads::Mutex::Lock lm (_process_lock);
579 session_remove_pending = true;
580 session_removal_countdown = 0;
581 session_removed.wait(_process_lock);
585 SessionHandlePtr::set_session (0);
593 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
596 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
604 /* called from a signal handler for SIGPIPE */
606 stop_metering_thread ();
612 AudioEngine::reset_timebase ()
615 if (_session->config.get_jack_time_master()) {
616 _backend->set_time_master (true);
618 _backend->set_time_master (false);
626 AudioEngine::destroy ()
633 AudioEngine::discover_backends ()
635 vector<std::string> backend_modules;
639 Glib::PatternSpec so_extension_pattern("*backend.so");
640 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
642 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
643 #if defined(DEBUG) || defined(_DEBUG)
644 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
646 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
649 Glib::PatternSpec dll_extension_pattern("*backend.dll");
652 find_files_matching_pattern (backend_modules, backend_search_path (),
653 so_extension_pattern);
655 find_files_matching_pattern (backend_modules, backend_search_path (),
656 dylib_extension_pattern);
658 find_files_matching_pattern (backend_modules, backend_search_path (),
659 dll_extension_pattern);
661 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
663 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
665 AudioBackendInfo* info;
667 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
669 if ((info = backend_discover (*i)) != 0) {
670 _backends.insert (make_pair (info->name, info));
674 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
676 return _backends.size();
680 AudioEngine::backend_discover (const string& path)
682 #ifdef PLATFORM_WINDOWS
683 // do not show popup dialog (e.g. missing libjack.dll)
684 // win7+ should use SetThreadErrorMode()
685 SetErrorMode(SEM_FAILCRITICALERRORS);
687 Glib::Module module (path);
688 #ifdef PLATFORM_WINDOWS
689 SetErrorMode(0); // reset to system default
691 AudioBackendInfo* info;
692 AudioBackendInfo* (*dfunc)(void);
696 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
697 Glib::Module::get_last_error()) << endmsg;
701 if (!module.get_symbol ("descriptor", func)) {
702 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
703 error << Glib::Module::get_last_error() << endmsg;
707 dfunc = (AudioBackendInfo* (*)(void))func;
709 if (!info->available()) {
713 module.make_resident ();
718 vector<const AudioBackendInfo*>
719 AudioEngine::available_backends() const
721 vector<const AudioBackendInfo*> r;
723 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
724 r.push_back (i->second);
731 AudioEngine::current_backend_name() const
734 return _backend->name();
740 AudioEngine::drop_backend ()
744 _backend->drop_device ();
750 boost::shared_ptr<AudioBackend>
751 AudioEngine::set_default_backend ()
753 if (_backends.empty()) {
754 return boost::shared_ptr<AudioBackend>();
757 return set_backend (_backends.begin()->first, "", "");
760 boost::shared_ptr<AudioBackend>
761 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
763 BackendMap::iterator b = _backends.find (name);
765 if (b == _backends.end()) {
766 return boost::shared_ptr<AudioBackend>();
772 if (b->second->instantiate (arg1, arg2)) {
773 throw failed_constructor ();
776 _backend = b->second->factory (*this);
778 } catch (exception& e) {
779 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
780 return boost::shared_ptr<AudioBackend>();
786 /* BACKEND PROXY WRAPPERS */
789 AudioEngine::start (bool for_latency)
799 _processed_frames = 0;
800 last_monitor_check = 0;
802 if (_backend->start (for_latency)) {
809 _session->set_frame_rate (_backend->sample_rate());
811 if (_session->config.get_jack_time_master()) {
812 _backend->set_time_master (true);
817 start_metering_thread ();
820 Running(); /* EMIT SIGNAL */
827 AudioEngine::stop (bool for_latency)
833 if (_session && _running) {
834 // it's not a halt, but should be handled the same way:
835 // disable record, stop transport and I/O processign but save the data.
836 _session->engine_halted ();
839 Glib::Threads::Mutex::Lock lm (_process_lock);
841 if (_backend->stop ()) {
846 _processed_frames = 0;
847 _measuring_latency = MeasureNone;
848 _latency_output_port = 0;
849 _latency_input_port = 0;
850 _started_for_latency = false;
851 stop_metering_thread ();
856 Stopped (); /* EMIT SIGNAL */
863 AudioEngine::freewheel (bool start_stop)
869 /* _freewheeling will be set when first Freewheel signal occurs */
871 return _backend->freewheel (start_stop);
875 AudioEngine::get_dsp_load() const
880 return _backend->dsp_load ();
884 AudioEngine::is_realtime() const
890 return _backend->is_realtime();
894 AudioEngine::connected() const
900 return _backend->available();
904 AudioEngine::transport_start ()
909 return _backend->transport_start ();
913 AudioEngine::transport_stop ()
918 return _backend->transport_stop ();
922 AudioEngine::transport_state ()
925 return TransportStopped;
927 return _backend->transport_state ();
931 AudioEngine::transport_locate (framepos_t pos)
936 return _backend->transport_locate (pos);
940 AudioEngine::transport_frame()
945 return _backend->transport_frame ();
949 AudioEngine::sample_rate () const
954 return _backend->sample_rate ();
958 AudioEngine::samples_per_cycle () const
963 return _backend->buffer_size ();
967 AudioEngine::usecs_per_cycle () const
972 return _backend->usecs_per_cycle ();
976 AudioEngine::raw_buffer_size (DataType t)
981 return _backend->raw_buffer_size (t);
985 AudioEngine::sample_time ()
990 return _backend->sample_time ();
994 AudioEngine::sample_time_at_cycle_start ()
999 return _backend->sample_time_at_cycle_start ();
1003 AudioEngine::samples_since_cycle_start ()
1008 return _backend->samples_since_cycle_start ();
1012 AudioEngine::get_sync_offset (pframes_t& offset) const
1017 return _backend->get_sync_offset (offset);
1021 AudioEngine::create_process_thread (boost::function<void()> func)
1026 return _backend->create_process_thread (func);
1030 AudioEngine::join_process_threads ()
1035 return _backend->join_process_threads ();
1039 AudioEngine::in_process_thread ()
1044 return _backend->in_process_thread ();
1048 AudioEngine::process_thread_count ()
1053 return _backend->process_thread_count ();
1057 AudioEngine::set_device_name (const std::string& name)
1062 return _backend->set_device_name (name);
1066 AudioEngine::set_sample_rate (float sr)
1071 return _backend->set_sample_rate (sr);
1075 AudioEngine::set_buffer_size (uint32_t bufsiz)
1080 return _backend->set_buffer_size (bufsiz);
1084 AudioEngine::set_interleaved (bool yn)
1089 return _backend->set_interleaved (yn);
1093 AudioEngine::set_input_channels (uint32_t ic)
1098 return _backend->set_input_channels (ic);
1102 AudioEngine::set_output_channels (uint32_t oc)
1107 return _backend->set_output_channels (oc);
1111 AudioEngine::set_systemic_input_latency (uint32_t il)
1116 return _backend->set_systemic_input_latency (il);
1120 AudioEngine::set_systemic_output_latency (uint32_t ol)
1125 return _backend->set_systemic_output_latency (ol);
1128 /* END OF BACKEND PROXY API */
1131 AudioEngine::thread_init_callback (void* arg)
1133 /* make sure that anybody who needs to know about this thread
1137 pthread_set_name (X_("audioengine"));
1139 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1141 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1142 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1144 AsyncMIDIPort::set_process_thread (pthread_self());
1147 /* the special thread created/managed by the backend */
1148 AudioEngine::instance()->_main_thread = new ProcessThread;
1153 AudioEngine::sync_callback (TransportState state, framepos_t position)
1156 return _session->backend_sync_callback (state, position);
1162 AudioEngine::freewheel_callback (bool onoff)
1164 _freewheeling = onoff;
1168 AudioEngine::latency_callback (bool for_playback)
1171 _session->update_latency (for_playback);
1176 AudioEngine::update_latencies ()
1179 _backend->update_latencies ();
1184 AudioEngine::halted_callback (const char* why)
1186 if (_in_destructor) {
1187 /* everything is under control */
1191 stop_metering_thread ();
1194 Port::PortDrop (); /* EMIT SIGNAL */
1196 if (!_started_for_latency) {
1197 Halted (why); /* EMIT SIGNAL */
1202 AudioEngine::setup_required () const
1205 if (_backend->info().already_configured())
1208 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1217 AudioEngine::prepare_for_latency_measurement ()
1220 _stopped_for_latency = true;
1225 _started_for_latency = true;
1233 AudioEngine::start_latency_detection (bool for_midi)
1236 if (prepare_for_latency_measurement ()) {
1241 PortEngine& pe (port_engine());
1249 /* find the ports we will connect to */
1251 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1252 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1259 /* create the ports we will use to read/write data */
1261 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
1265 if (pe.connect (_latency_output_port, _latency_output_name)) {
1266 pe.unregister_port (_latency_output_port);
1271 const string portname ("latency_in");
1272 if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
1273 pe.unregister_port (_latency_input_port);
1274 pe.unregister_port (_latency_output_port);
1278 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1279 pe.unregister_port (_latency_input_port);
1280 pe.unregister_port (_latency_output_port);
1285 _mididm = new MIDIDM (sample_rate());
1289 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1293 if (pe.connect (_latency_output_port, _latency_output_name)) {
1294 pe.unregister_port (_latency_output_port);
1299 const string portname ("latency_in");
1300 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1301 pe.unregister_port (_latency_input_port);
1302 pe.unregister_port (_latency_output_port);
1306 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1307 pe.unregister_port (_latency_input_port);
1308 pe.unregister_port (_latency_output_port);
1313 _mtdm = new MTDM (sample_rate());
1318 _latency_signal_latency = 0;
1319 lr = pe.get_latency_range (in, false);
1320 _latency_signal_latency = lr.max;
1321 lr = pe.get_latency_range (out, true);
1322 _latency_signal_latency += lr.max;
1324 /* all created and connected, lets go */
1325 _latency_flush_frames = samples_per_cycle();
1326 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1332 AudioEngine::stop_latency_detection ()
1334 _measuring_latency = MeasureNone;
1336 if (_latency_output_port) {
1337 port_engine().unregister_port (_latency_output_port);
1338 _latency_output_port = 0;
1340 if (_latency_input_port) {
1341 port_engine().unregister_port (_latency_input_port);
1342 _latency_input_port = 0;
1347 if (_stopped_for_latency) {
1351 _stopped_for_latency = false;
1352 _started_for_latency = false;
1356 AudioEngine::set_latency_output_port (const string& name)
1358 _latency_output_name = name;
1362 AudioEngine::set_latency_input_port (const string& name)
1364 _latency_input_name = name;