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 _thread_init_callback (void * /*arg*/)
121 /* make sure that anybody who needs to know about this thread
125 pthread_set_name (X_("audioengine"));
127 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Audioengine"), 4096);
128 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("Audioengine"), 128);
130 SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
132 AsyncMIDIPort::set_process_thread (pthread_self());
136 AudioEngine::split_cycle (pframes_t offset)
138 /* caller must hold process lock */
140 Port::increment_global_port_buffer_offset (offset);
142 /* tell all Ports that we're going to start a new (split) cycle */
144 boost::shared_ptr<Ports> p = ports.reader();
146 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
147 i->second->cycle_split ();
152 AudioEngine::sample_rate_change (pframes_t nframes)
154 /* check for monitor input change every 1/10th of second */
156 monitor_check_interval = nframes / 10;
157 last_monitor_check = 0;
160 _session->set_frame_rate (nframes);
163 SampleRateChanged (nframes); /* EMIT SIGNAL */
169 AudioEngine::buffer_size_change (pframes_t bufsiz)
172 _session->set_block_size (bufsiz);
173 last_monitor_check = 0;
176 BufferSizeChanged (bufsiz); /* EMIT SIGNAL */
181 /** Method called by our ::process_thread when there is work to be done.
182 * @param nframes Number of frames to process.
185 __attribute__((annotate("realtime")))
188 AudioEngine::process_callback (pframes_t nframes)
190 Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
195 /// The number of frames that will have been processed when we've finished
196 pframes_t next_processed_frames;
198 /* handle wrap around of total frames counter */
200 if (max_framepos - _processed_frames < nframes) {
201 next_processed_frames = nframes - (max_framepos - _processed_frames);
203 next_processed_frames = _processed_frames + nframes;
207 /* return having done nothing */
208 _processed_frames = next_processed_frames;
212 bool return_after_remove_check = false;
214 if (_measuring_latency == MeasureAudio && _mtdm) {
215 /* run a normal cycle from the perspective of the PortManager
216 so that we get silence on all registered ports.
218 we overwrite the silence on the two ports used for latency
222 PortManager::cycle_start (nframes);
223 PortManager::silence (nframes);
225 if (_latency_input_port && _latency_output_port) {
226 PortEngine& pe (port_engine());
228 Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
229 Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
231 _mtdm->process (nframes, in, out);
234 PortManager::cycle_end (nframes);
235 return_after_remove_check = true;
237 } else if (_measuring_latency == MeasureMIDI && _mididm) {
238 /* run a normal cycle from the perspective of the PortManager
239 so that we get silence on all registered ports.
241 we overwrite the silence on the two ports used for latency
245 PortManager::cycle_start (nframes);
246 PortManager::silence (nframes);
248 if (_latency_input_port && _latency_output_port) {
249 PortEngine& pe (port_engine());
251 _mididm->process (nframes, pe,
252 pe.get_buffer (_latency_input_port, nframes),
253 pe.get_buffer (_latency_output_port, nframes));
256 PortManager::cycle_end (nframes);
257 return_after_remove_check = true;
259 } else if (_latency_flush_frames) {
261 /* wait for the appropriate duration for the MTDM signal to
262 * drain from the ports before we revert to normal behaviour.
265 PortManager::cycle_start (nframes);
266 PortManager::silence (nframes);
267 PortManager::cycle_end (nframes);
269 if (_latency_flush_frames > nframes) {
270 _latency_flush_frames -= nframes;
272 _latency_flush_frames = 0;
275 return_after_remove_check = true;
278 if (session_remove_pending) {
280 /* perform the actual session removal */
282 if (session_removal_countdown < 0) {
284 /* fade out over 1 second */
285 session_removal_countdown = sample_rate()/2;
286 session_removal_gain = 1.0;
287 session_removal_gain_step = 1.0/session_removal_countdown;
289 } else if (session_removal_countdown > 0) {
291 /* we'll be fading audio out.
293 if this is the last time we do this as part
294 of session removal, do a MIDI panic now
295 to get MIDI stopped. This relies on the fact
296 that "immediate data" (aka "out of band data") from
297 MIDI tracks is *appended* after any other data,
298 so that it emerges after any outbound note ons, etc.
301 if (session_removal_countdown <= nframes) {
302 _session->midi_panic ();
308 session_removal_countdown = -1; // reset to "not in progress"
309 session_remove_pending = false;
310 session_removed.signal(); // wakes up thread that initiated session removal
314 if (return_after_remove_check) {
320 if (!_freewheeling) {
321 PortManager::cycle_start (nframes);
322 PortManager::cycle_end (nframes);
325 _processed_frames = next_processed_frames;
330 /* tell all relevant objects that we're starting a new cycle */
332 InternalSend::CycleStart (nframes);
334 /* tell all Ports that we're starting a new cycle */
336 PortManager::cycle_start (nframes);
338 /* test if we are freewheeling and there are freewheel signals connected.
339 ardour should act normally even when freewheeling unless /it/ is
340 exporting (which is what Freewheel.empty() tests for).
343 if (_freewheeling && !Freewheel.empty()) {
347 _session->process (nframes);
356 _processed_frames = next_processed_frames;
360 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
362 PortManager::check_monitoring ();
363 last_monitor_check = next_processed_frames;
366 if (_session->silent()) {
367 PortManager::silence (nframes);
370 if (session_remove_pending && session_removal_countdown) {
372 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
374 if (session_removal_countdown > nframes) {
375 session_removal_countdown -= nframes;
377 session_removal_countdown = 0;
380 session_removal_gain -= (nframes * session_removal_gain_step);
383 PortManager::cycle_end (nframes);
385 _processed_frames = next_processed_frames;
394 AudioEngine::request_backend_reset()
396 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
397 g_atomic_int_inc (&_hw_reset_request_count);
398 _hw_reset_condition.signal ();
403 AudioEngine::do_reset_backend()
405 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
407 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
409 while (!_stop_hw_reset_processing) {
411 if (_hw_reset_request_count && _backend) {
413 _reset_request_lock.unlock();
415 Glib::Threads::RecMutex::Lock pl (_state_lock);
417 g_atomic_int_dec_and_test (&_hw_reset_request_count);
419 std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
421 // backup the device name
422 std::string name = _backend->device_name ();
424 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
427 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
428 if ( 0 == _backend->reset_device () ) {
430 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
433 // inform about possible changes
434 BufferSizeChanged (_backend->buffer_size() );
439 std::cout << "AudioEngine::RESET::Done." << std::endl;
441 _reset_request_lock.lock();
445 _hw_reset_condition.wait (_reset_request_lock);
453 AudioEngine::request_device_list_update()
455 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
456 g_atomic_int_inc (&_hw_devicelist_update_count);
457 _hw_devicelist_update_condition.signal ();
462 AudioEngine::do_devicelist_update()
464 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
466 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
468 while (!_stop_hw_devicelist_processing) {
470 if (_hw_devicelist_update_count) {
472 _devicelist_update_lock.unlock();
474 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
475 DeviceListChanged (); /* EMIT SIGNAL */
477 _devicelist_update_lock.lock();
480 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
487 AudioEngine::start_hw_event_processing()
489 if (_hw_reset_event_thread == 0) {
490 g_atomic_int_set(&_hw_reset_request_count, 0);
491 g_atomic_int_set(&_stop_hw_reset_processing, 0);
492 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
495 if (_hw_devicelist_update_thread == 0) {
496 g_atomic_int_set(&_hw_devicelist_update_count, 0);
497 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
498 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
504 AudioEngine::stop_hw_event_processing()
506 if (_hw_reset_event_thread) {
507 g_atomic_int_set(&_stop_hw_reset_processing, 1);
508 g_atomic_int_set(&_hw_reset_request_count, 0);
509 _hw_reset_condition.signal ();
510 _hw_reset_event_thread->join ();
511 _hw_reset_event_thread = 0;
514 if (_hw_devicelist_update_thread) {
515 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
516 g_atomic_int_set(&_hw_devicelist_update_count, 0);
517 _hw_devicelist_update_condition.signal ();
518 _hw_devicelist_update_thread->join ();
519 _hw_devicelist_update_thread = 0;
527 AudioEngine::stop_metering_thread ()
529 if (m_meter_thread) {
530 g_atomic_int_set (&m_meter_exit, 1);
531 m_meter_thread->join ();
537 AudioEngine::start_metering_thread ()
539 if (m_meter_thread == 0) {
540 g_atomic_int_set (&m_meter_exit, 0);
541 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
546 AudioEngine::meter_thread ()
548 pthread_set_name (X_("meter"));
551 Glib::usleep (10000); /* 1/100th sec interval */
552 if (g_atomic_int_get(&m_meter_exit)) {
560 AudioEngine::set_session (Session *s)
562 Glib::Threads::Mutex::Lock pl (_process_lock);
564 SessionHandlePtr::set_session (s);
568 pframes_t blocksize = samples_per_cycle ();
570 PortManager::cycle_start (blocksize);
572 _session->process (blocksize);
573 _session->process (blocksize);
574 _session->process (blocksize);
575 _session->process (blocksize);
576 _session->process (blocksize);
577 _session->process (blocksize);
578 _session->process (blocksize);
579 _session->process (blocksize);
581 PortManager::cycle_end (blocksize);
586 AudioEngine::remove_session ()
588 Glib::Threads::Mutex::Lock lm (_process_lock);
593 session_remove_pending = true;
594 session_removal_countdown = 0;
595 session_removed.wait(_process_lock);
599 SessionHandlePtr::set_session (0);
607 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
610 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
618 /* called from a signal handler for SIGPIPE */
620 stop_metering_thread ();
626 AudioEngine::reset_timebase ()
629 if (_session->config.get_jack_time_master()) {
630 _backend->set_time_master (true);
632 _backend->set_time_master (false);
640 AudioEngine::destroy ()
647 AudioEngine::discover_backends ()
649 vector<std::string> backend_modules;
653 Glib::PatternSpec so_extension_pattern("*backend.so");
654 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
656 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
657 #if defined(DEBUG) || defined(_DEBUG)
658 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
660 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
663 Glib::PatternSpec dll_extension_pattern("*backend.dll");
666 find_files_matching_pattern (backend_modules, backend_search_path (),
667 so_extension_pattern);
669 find_files_matching_pattern (backend_modules, backend_search_path (),
670 dylib_extension_pattern);
672 find_files_matching_pattern (backend_modules, backend_search_path (),
673 dll_extension_pattern);
675 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
677 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
679 AudioBackendInfo* info;
681 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
683 if ((info = backend_discover (*i)) != 0) {
684 _backends.insert (make_pair (info->name, info));
688 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
690 return _backends.size();
694 AudioEngine::backend_discover (const string& path)
696 Glib::Module module (path);
697 AudioBackendInfo* info;
698 AudioBackendInfo* (*dfunc)(void);
702 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
703 Glib::Module::get_last_error()) << endmsg;
707 if (!module.get_symbol ("descriptor", func)) {
708 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
709 error << Glib::Module::get_last_error() << endmsg;
713 module.make_resident ();
715 dfunc = (AudioBackendInfo* (*)(void))func;
721 vector<const AudioBackendInfo*>
722 AudioEngine::available_backends() const
724 vector<const AudioBackendInfo*> r;
726 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
727 r.push_back (i->second);
734 AudioEngine::current_backend_name() const
737 return _backend->name();
743 AudioEngine::drop_backend ()
747 _backend->drop_device ();
753 boost::shared_ptr<AudioBackend>
754 AudioEngine::set_default_backend ()
756 if (_backends.empty()) {
757 return boost::shared_ptr<AudioBackend>();
760 return set_backend (_backends.begin()->first, "", "");
763 boost::shared_ptr<AudioBackend>
764 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
766 BackendMap::iterator b = _backends.find (name);
768 if (b == _backends.end()) {
769 return boost::shared_ptr<AudioBackend>();
775 if (b->second->instantiate (arg1, arg2)) {
776 throw failed_constructor ();
779 _backend = b->second->factory (*this);
781 } catch (exception& e) {
782 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
783 return boost::shared_ptr<AudioBackend>();
789 /* BACKEND PROXY WRAPPERS */
792 AudioEngine::start (bool for_latency)
802 _processed_frames = 0;
803 last_monitor_check = 0;
805 if (_backend->start (for_latency)) {
812 _session->set_frame_rate (_backend->sample_rate());
814 if (_session->config.get_jack_time_master()) {
815 _backend->set_time_master (true);
820 start_metering_thread ();
823 Running(); /* EMIT SIGNAL */
830 AudioEngine::stop (bool for_latency)
836 if (_session && _running) {
837 // it's not a halt, but should be handled the same way:
838 // disable record, stop transport and I/O processign but save the data.
839 _session->engine_halted ();
842 Glib::Threads::Mutex::Lock lm (_process_lock);
844 if (_backend->stop ()) {
849 _processed_frames = 0;
850 _measuring_latency = MeasureNone;
851 _latency_output_port = 0;
852 _latency_input_port = 0;
853 _started_for_latency = false;
854 stop_metering_thread ();
859 Stopped (); /* EMIT SIGNAL */
866 AudioEngine::freewheel (bool start_stop)
872 /* _freewheeling will be set when first Freewheel signal occurs */
874 return _backend->freewheel (start_stop);
878 AudioEngine::get_dsp_load() const
883 return _backend->dsp_load ();
887 AudioEngine::is_realtime() const
893 return _backend->is_realtime();
897 AudioEngine::connected() const
903 return _backend->available();
907 AudioEngine::transport_start ()
912 return _backend->transport_start ();
916 AudioEngine::transport_stop ()
921 return _backend->transport_stop ();
925 AudioEngine::transport_state ()
928 return TransportStopped;
930 return _backend->transport_state ();
934 AudioEngine::transport_locate (framepos_t pos)
939 return _backend->transport_locate (pos);
943 AudioEngine::transport_frame()
948 return _backend->transport_frame ();
952 AudioEngine::sample_rate () const
957 return _backend->sample_rate ();
961 AudioEngine::samples_per_cycle () const
966 return _backend->buffer_size ();
970 AudioEngine::usecs_per_cycle () const
975 return _backend->usecs_per_cycle ();
979 AudioEngine::raw_buffer_size (DataType t)
984 return _backend->raw_buffer_size (t);
988 AudioEngine::sample_time ()
993 return _backend->sample_time ();
997 AudioEngine::sample_time_at_cycle_start ()
1002 return _backend->sample_time_at_cycle_start ();
1006 AudioEngine::samples_since_cycle_start ()
1011 return _backend->samples_since_cycle_start ();
1015 AudioEngine::get_sync_offset (pframes_t& offset) const
1020 return _backend->get_sync_offset (offset);
1024 AudioEngine::create_process_thread (boost::function<void()> func)
1029 return _backend->create_process_thread (func);
1033 AudioEngine::join_process_threads ()
1038 return _backend->join_process_threads ();
1042 AudioEngine::in_process_thread ()
1047 return _backend->in_process_thread ();
1051 AudioEngine::process_thread_count ()
1056 return _backend->process_thread_count ();
1060 AudioEngine::set_device_name (const std::string& name)
1065 return _backend->set_device_name (name);
1069 AudioEngine::set_sample_rate (float sr)
1074 return _backend->set_sample_rate (sr);
1078 AudioEngine::set_buffer_size (uint32_t bufsiz)
1083 return _backend->set_buffer_size (bufsiz);
1087 AudioEngine::set_interleaved (bool yn)
1092 return _backend->set_interleaved (yn);
1096 AudioEngine::set_input_channels (uint32_t ic)
1101 return _backend->set_input_channels (ic);
1105 AudioEngine::set_output_channels (uint32_t oc)
1110 return _backend->set_output_channels (oc);
1114 AudioEngine::set_systemic_input_latency (uint32_t il)
1119 return _backend->set_systemic_input_latency (il);
1123 AudioEngine::set_systemic_output_latency (uint32_t ol)
1128 return _backend->set_systemic_output_latency (ol);
1131 /* END OF BACKEND PROXY API */
1134 AudioEngine::thread_init_callback (void* arg)
1136 /* make sure that anybody who needs to know about this thread
1140 pthread_set_name (X_("audioengine"));
1142 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1143 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1145 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1147 AsyncMIDIPort::set_process_thread (pthread_self());
1150 /* the special thread created/managed by the backend */
1151 AudioEngine::instance()->_main_thread = new ProcessThread;
1156 AudioEngine::sync_callback (TransportState state, framepos_t position)
1159 return _session->backend_sync_callback (state, position);
1165 AudioEngine::freewheel_callback (bool onoff)
1167 _freewheeling = onoff;
1171 AudioEngine::latency_callback (bool for_playback)
1174 _session->update_latency (for_playback);
1179 AudioEngine::update_latencies ()
1182 _backend->update_latencies ();
1187 AudioEngine::halted_callback (const char* why)
1189 if (_in_destructor) {
1190 /* everything is under control */
1194 stop_metering_thread ();
1197 Port::PortDrop (); /* EMIT SIGNAL */
1199 if (!_started_for_latency) {
1200 Halted (why); /* EMIT SIGNAL */
1205 AudioEngine::setup_required () const
1208 if (_backend->info().already_configured())
1211 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1220 AudioEngine::prepare_for_latency_measurement ()
1223 _stopped_for_latency = true;
1228 _started_for_latency = true;
1236 AudioEngine::start_latency_detection (bool for_midi)
1239 if (prepare_for_latency_measurement ()) {
1244 PortEngine& pe (port_engine());
1252 /* find the ports we will connect to */
1254 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1255 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1262 /* create the ports we will use to read/write data */
1264 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
1268 if (pe.connect (_latency_output_port, _latency_output_name)) {
1269 pe.unregister_port (_latency_output_port);
1274 const string portname ("latency_in");
1275 if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
1276 pe.unregister_port (_latency_input_port);
1277 pe.unregister_port (_latency_output_port);
1281 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1282 pe.unregister_port (_latency_input_port);
1283 pe.unregister_port (_latency_output_port);
1288 _mididm = new MIDIDM (sample_rate());
1292 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1296 if (pe.connect (_latency_output_port, _latency_output_name)) {
1297 pe.unregister_port (_latency_output_port);
1302 const string portname ("latency_in");
1303 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1304 pe.unregister_port (_latency_input_port);
1305 pe.unregister_port (_latency_output_port);
1309 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1310 pe.unregister_port (_latency_input_port);
1311 pe.unregister_port (_latency_output_port);
1316 _mtdm = new MTDM (sample_rate());
1321 _latency_signal_latency = 0;
1322 lr = pe.get_latency_range (in, false);
1323 _latency_signal_latency = lr.max;
1324 lr = pe.get_latency_range (out, true);
1325 _latency_signal_latency += lr.max;
1327 /* all created and connected, lets go */
1328 _latency_flush_frames = samples_per_cycle();
1329 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1335 AudioEngine::stop_latency_detection ()
1337 _measuring_latency = MeasureNone;
1339 if (_latency_output_port) {
1340 port_engine().unregister_port (_latency_output_port);
1341 _latency_output_port = 0;
1343 if (_latency_input_port) {
1344 port_engine().unregister_port (_latency_input_port);
1345 _latency_input_port = 0;
1350 if (_stopped_for_latency) {
1354 _stopped_for_latency = false;
1355 _started_for_latency = false;
1359 AudioEngine::set_latency_output_port (const string& name)
1361 _latency_output_name = name;
1365 AudioEngine::set_latency_input_port (const string& name)
1367 _latency_input_name = name;