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.
28 #include <glibmm/timer.h>
29 #include <glibmm/pattern.h>
30 #include <glibmm/module.h>
33 #include "pbd/file_utils.h"
34 #include "pbd/pthread_utils.h"
35 #include "pbd/stacktrace.h"
36 #include "pbd/unknown_type.h"
38 #include "midi++/port.h"
39 #include "midi++/mmc.h"
41 #include "ardour/async_midi_port.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audio_backend.h"
44 #include "ardour/audioengine.h"
45 #include "ardour/search_paths.h"
46 #include "ardour/buffer.h"
47 #include "ardour/cycle_timer.h"
48 #include "ardour/internal_send.h"
49 #include "ardour/meter.h"
50 #include "ardour/midi_port.h"
51 #include "ardour/midiport_manager.h"
52 #include "ardour/mididm.h"
53 #include "ardour/mtdm.h"
54 #include "ardour/port.h"
55 #include "ardour/process_thread.h"
56 #include "ardour/session.h"
61 using namespace ARDOUR;
64 AudioEngine* AudioEngine::_instance = 0;
67 #define SILENCE_AFTER_SECONDS 600
70 AudioEngine::AudioEngine ()
71 : session_remove_pending (false)
72 , session_removal_countdown (-1)
74 , _freewheeling (false)
75 , monitor_check_interval (INT32_MAX)
76 , last_monitor_check (0)
77 , _processed_frames (0)
82 , _measuring_latency (MeasureNone)
83 , _latency_input_port (0)
84 , _latency_output_port (0)
85 , _latency_flush_frames (0)
86 , _latency_signal_latency (0)
87 , _stopped_for_latency (false)
88 , _started_for_latency (false)
89 , _in_destructor (false)
90 , _hw_reset_event_thread(0)
91 , _hw_reset_request_count(0)
92 , _stop_hw_reset_processing(0)
93 , _hw_devicelist_update_thread(0)
94 , _hw_devicelist_update_count(0)
95 , _stop_hw_devicelist_processing(0)
96 #ifdef SILENCE_AFTER_SECONDS
97 , _silence_countdown (0)
98 , _silence_hit_cnt (0)
101 reset_silence_countdown ();
102 start_hw_event_processing();
103 discover_backends ();
106 AudioEngine::~AudioEngine ()
108 _in_destructor = true;
109 stop_hw_event_processing();
111 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
112 i->second->deinstantiate();
117 AudioEngine::create ()
123 _instance = new AudioEngine ();
129 AudioEngine::split_cycle (pframes_t offset)
131 /* caller must hold process lock */
133 Port::increment_global_port_buffer_offset (offset);
135 /* tell all Ports that we're going to start a new (split) cycle */
137 boost::shared_ptr<Ports> p = ports.reader();
139 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
140 i->second->cycle_split ();
145 AudioEngine::sample_rate_change (pframes_t nframes)
147 /* check for monitor input change every 1/10th of second */
149 monitor_check_interval = nframes / 10;
150 last_monitor_check = 0;
153 _session->set_frame_rate (nframes);
156 SampleRateChanged (nframes); /* EMIT SIGNAL */
158 #ifdef SILENCE_AFTER_SECONDS
159 _silence_countdown = nframes * SILENCE_AFTER_SECONDS;
166 AudioEngine::buffer_size_change (pframes_t bufsiz)
169 _session->set_block_size (bufsiz);
170 last_monitor_check = 0;
173 BufferSizeChanged (bufsiz); /* EMIT SIGNAL */
178 /** Method called by our ::process_thread when there is work to be done.
179 * @param nframes Number of frames to process.
182 __attribute__((annotate("realtime")))
185 AudioEngine::process_callback (pframes_t nframes)
187 Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
192 /// The number of frames that will have been processed when we've finished
193 pframes_t next_processed_frames;
195 /* handle wrap around of total frames counter */
197 if (max_framepos - _processed_frames < nframes) {
198 next_processed_frames = nframes - (max_framepos - _processed_frames);
200 next_processed_frames = _processed_frames + nframes;
204 /* return having done nothing */
208 /* really only JACK requires this
209 * (other backends clear the output buffers
210 * before the process_callback. it may even be
211 * jack/alsa only). but better safe than sorry.
213 PortManager::silence_outputs (nframes);
217 bool return_after_remove_check = false;
219 if (_measuring_latency == MeasureAudio && _mtdm) {
220 /* run a normal cycle from the perspective of the PortManager
221 so that we get silence on all registered ports.
223 we overwrite the silence on the two ports used for latency
227 PortManager::cycle_start (nframes);
228 PortManager::silence (nframes);
230 if (_latency_input_port && _latency_output_port) {
231 PortEngine& pe (port_engine());
233 Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
234 Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
236 _mtdm->process (nframes, in, out);
239 PortManager::cycle_end (nframes);
240 return_after_remove_check = true;
242 } else if (_measuring_latency == MeasureMIDI && _mididm) {
243 /* run a normal cycle from the perspective of the PortManager
244 so that we get silence on all registered ports.
246 we overwrite the silence on the two ports used for latency
250 PortManager::cycle_start (nframes);
251 PortManager::silence (nframes);
253 if (_latency_input_port && _latency_output_port) {
254 PortEngine& pe (port_engine());
256 _mididm->process (nframes, pe,
257 pe.get_buffer (_latency_input_port, nframes),
258 pe.get_buffer (_latency_output_port, nframes));
261 PortManager::cycle_end (nframes);
262 return_after_remove_check = true;
264 } else if (_latency_flush_frames) {
266 /* wait for the appropriate duration for the MTDM signal to
267 * drain from the ports before we revert to normal behaviour.
270 PortManager::cycle_start (nframes);
271 PortManager::silence (nframes);
272 PortManager::cycle_end (nframes);
274 if (_latency_flush_frames > nframes) {
275 _latency_flush_frames -= nframes;
277 _latency_flush_frames = 0;
280 return_after_remove_check = true;
283 if (session_remove_pending) {
285 /* perform the actual session removal */
287 if (session_removal_countdown < 0) {
289 /* fade out over 1 second */
290 session_removal_countdown = sample_rate()/2;
291 session_removal_gain = GAIN_COEFF_UNITY;
292 session_removal_gain_step = 1.0/session_removal_countdown;
294 } else if (session_removal_countdown > 0) {
296 /* we'll be fading audio out.
298 if this is the last time we do this as part
299 of session removal, do a MIDI panic now
300 to get MIDI stopped. This relies on the fact
301 that "immediate data" (aka "out of band data") from
302 MIDI tracks is *appended* after any other data,
303 so that it emerges after any outbound note ons, etc.
306 if (session_removal_countdown <= nframes) {
307 _session->midi_panic ();
313 session_removal_countdown = -1; // reset to "not in progress"
314 session_remove_pending = false;
315 session_removed.signal(); // wakes up thread that initiated session removal
319 if (return_after_remove_check) {
325 if (!_freewheeling) {
326 PortManager::cycle_start (nframes);
327 PortManager::cycle_end (nframes);
330 _processed_frames = next_processed_frames;
335 /* tell all relevant objects that we're starting a new cycle */
337 InternalSend::CycleStart (nframes);
339 /* tell all Ports that we're starting a new cycle */
341 PortManager::cycle_start (nframes);
343 /* test if we are freewheeling and there are freewheel signals connected.
344 ardour should act normally even when freewheeling unless /it/ is
345 exporting (which is what Freewheel.empty() tests for).
348 if (_freewheeling && !Freewheel.empty()) {
351 _session->process (nframes);
355 PortManager::cycle_end (nframes);
360 _processed_frames = next_processed_frames;
364 if (last_monitor_check + monitor_check_interval < next_processed_frames) {
366 PortManager::check_monitoring ();
367 last_monitor_check = next_processed_frames;
370 #ifdef SILENCE_AFTER_SECONDS
372 bool was_silent = (_silence_countdown == 0);
374 if (_silence_countdown >= nframes) {
375 _silence_countdown -= nframes;
377 _silence_countdown = 0;
380 if (!was_silent && _silence_countdown == 0) {
382 BecameSilent (); /* EMIT SIGNAL */
385 if (_silence_countdown == 0 || _session->silent()) {
386 PortManager::silence (nframes);
390 if (_session->silent()) {
391 PortManager::silence (nframes);
395 if (session_remove_pending && session_removal_countdown) {
397 PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
399 if (session_removal_countdown > nframes) {
400 session_removal_countdown -= nframes;
402 session_removal_countdown = 0;
405 session_removal_gain -= (nframes * session_removal_gain_step);
408 PortManager::cycle_end (nframes);
410 _processed_frames = next_processed_frames;
418 AudioEngine::reset_silence_countdown ()
420 #ifdef SILENCE_AFTER_SECONDS
421 double sr = 48000; /* default in case there is no backend */
425 _silence_countdown = max (60 * sr, /* 60 seconds */
426 sr * (SILENCE_AFTER_SECONDS / ::pow (2.0, (double) _silence_hit_cnt)));
432 AudioEngine::launch_device_control_app()
434 if (_state_lock.trylock () ) {
435 _backend->launch_control_app ();
436 _state_lock.unlock ();
442 AudioEngine::request_backend_reset()
444 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
445 g_atomic_int_inc (&_hw_reset_request_count);
446 _hw_reset_condition.signal ();
450 AudioEngine::backend_reset_requested()
452 return g_atomic_int_get (&_hw_reset_request_count);
456 AudioEngine::do_reset_backend()
458 SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
460 Glib::Threads::Mutex::Lock guard (_reset_request_lock);
462 while (!_stop_hw_reset_processing) {
464 if (g_atomic_int_get (&_hw_reset_request_count) != 0 && _backend) {
466 _reset_request_lock.unlock();
468 Glib::Threads::RecMutex::Lock pl (_state_lock);
469 g_atomic_int_dec_and_test (&_hw_reset_request_count);
471 std::cout << "AudioEngine::RESET::Reset request processing. Requests left: " << _hw_reset_request_count << std::endl;
472 DeviceResetStarted(); // notify about device reset to be started
474 // backup the device name
475 std::string name = _backend->device_name ();
477 std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
480 std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
481 if ( 0 == _backend->reset_device () ) {
483 std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
486 // inform about possible changes
487 BufferSizeChanged (_backend->buffer_size() );
492 std::cout << "AudioEngine::RESET::Done." << std::endl;
494 _reset_request_lock.lock();
498 _hw_reset_condition.wait (_reset_request_lock);
504 AudioEngine::request_device_list_update()
506 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
507 g_atomic_int_inc (&_hw_devicelist_update_count);
508 _hw_devicelist_update_condition.signal ();
513 AudioEngine::do_devicelist_update()
515 SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
517 Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
519 while (!_stop_hw_devicelist_processing) {
521 if (_hw_devicelist_update_count) {
523 _devicelist_update_lock.unlock();
525 g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
526 DeviceListChanged (); /* EMIT SIGNAL */
528 _devicelist_update_lock.lock();
531 _hw_devicelist_update_condition.wait (_devicelist_update_lock);
538 AudioEngine::start_hw_event_processing()
540 if (_hw_reset_event_thread == 0) {
541 g_atomic_int_set(&_hw_reset_request_count, 0);
542 g_atomic_int_set(&_stop_hw_reset_processing, 0);
543 _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
546 if (_hw_devicelist_update_thread == 0) {
547 g_atomic_int_set(&_hw_devicelist_update_count, 0);
548 g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
549 _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
555 AudioEngine::stop_hw_event_processing()
557 if (_hw_reset_event_thread) {
558 g_atomic_int_set(&_stop_hw_reset_processing, 1);
559 g_atomic_int_set(&_hw_reset_request_count, 0);
560 _hw_reset_condition.signal ();
561 _hw_reset_event_thread->join ();
562 _hw_reset_event_thread = 0;
565 if (_hw_devicelist_update_thread) {
566 g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
567 g_atomic_int_set(&_hw_devicelist_update_count, 0);
568 _hw_devicelist_update_condition.signal ();
569 _hw_devicelist_update_thread->join ();
570 _hw_devicelist_update_thread = 0;
577 AudioEngine::set_session (Session *s)
579 Glib::Threads::Mutex::Lock pl (_process_lock);
581 SessionHandlePtr::set_session (s);
585 pframes_t blocksize = samples_per_cycle ();
587 PortManager::cycle_start (blocksize);
589 _session->process (blocksize);
590 _session->process (blocksize);
591 _session->process (blocksize);
592 _session->process (blocksize);
593 _session->process (blocksize);
594 _session->process (blocksize);
595 _session->process (blocksize);
596 _session->process (blocksize);
598 PortManager::cycle_end (blocksize);
603 AudioEngine::remove_session ()
605 Glib::Threads::Mutex::Lock lm (_process_lock);
610 session_remove_pending = true;
611 session_removal_countdown = 0;
612 session_removed.wait(_process_lock);
616 SessionHandlePtr::set_session (0);
624 AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
627 _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
635 /* called from a signal handler for SIGPIPE */
640 AudioEngine::reset_timebase ()
643 if (_session->config.get_jack_time_master()) {
644 _backend->set_time_master (true);
646 _backend->set_time_master (false);
654 AudioEngine::destroy ()
661 AudioEngine::discover_backends ()
663 vector<std::string> backend_modules;
667 Glib::PatternSpec so_extension_pattern("*backend.so");
668 Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
670 #if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
671 #if defined(DEBUG) || defined(_DEBUG)
672 Glib::PatternSpec dll_extension_pattern("*backendD.dll");
674 Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
677 Glib::PatternSpec dll_extension_pattern("*backend.dll");
680 find_files_matching_pattern (backend_modules, backend_search_path (),
681 so_extension_pattern);
683 find_files_matching_pattern (backend_modules, backend_search_path (),
684 dylib_extension_pattern);
686 find_files_matching_pattern (backend_modules, backend_search_path (),
687 dll_extension_pattern);
689 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
691 for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
693 AudioBackendInfo* info;
695 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
697 if ((info = backend_discover (*i)) != 0) {
698 _backends.insert (make_pair (info->name, info));
702 DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
704 return _backends.size();
708 AudioEngine::backend_discover (const string& path)
710 #ifdef PLATFORM_WINDOWS
711 // do not show popup dialog (e.g. missing libjack.dll)
712 // win7+ should use SetThreadErrorMode()
713 SetErrorMode(SEM_FAILCRITICALERRORS);
715 Glib::Module module (path);
716 #ifdef PLATFORM_WINDOWS
717 SetErrorMode(0); // reset to system default
719 AudioBackendInfo* info;
720 AudioBackendInfo* (*dfunc)(void);
724 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
725 Glib::Module::get_last_error()) << endmsg;
729 if (!module.get_symbol ("descriptor", func)) {
730 error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
731 error << Glib::Module::get_last_error() << endmsg;
735 dfunc = (AudioBackendInfo* (*)(void))func;
737 if (!info->available()) {
741 module.make_resident ();
746 vector<const AudioBackendInfo*>
747 AudioEngine::available_backends() const
749 vector<const AudioBackendInfo*> r;
751 for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
752 r.push_back (i->second);
759 AudioEngine::current_backend_name() const
762 return _backend->name();
768 AudioEngine::drop_backend ()
772 _backend->drop_device ();
778 boost::shared_ptr<AudioBackend>
779 AudioEngine::set_default_backend ()
781 if (_backends.empty()) {
782 return boost::shared_ptr<AudioBackend>();
785 return set_backend (_backends.begin()->first, "", "");
788 boost::shared_ptr<AudioBackend>
789 AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
791 BackendMap::iterator b = _backends.find (name);
793 if (b == _backends.end()) {
794 return boost::shared_ptr<AudioBackend>();
800 if (b->second->instantiate (arg1, arg2)) {
801 throw failed_constructor ();
804 _backend = b->second->factory (*this);
806 } catch (exception& e) {
807 error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
808 return boost::shared_ptr<AudioBackend>();
814 /* BACKEND PROXY WRAPPERS */
817 AudioEngine::start (bool for_latency)
827 _processed_frames = 0;
828 last_monitor_check = 0;
830 if (_backend->start (for_latency)) {
837 _session->set_frame_rate (_backend->sample_rate());
839 if (_session->config.get_jack_time_master()) {
840 _backend->set_time_master (true);
846 Running(); /* EMIT SIGNAL */
853 AudioEngine::stop (bool for_latency)
859 if (_session && _running) {
860 // it's not a halt, but should be handled the same way:
861 // disable record, stop transport and I/O processign but save the data.
862 _session->engine_halted ();
865 Glib::Threads::Mutex::Lock lm (_process_lock);
867 if (_backend->stop ()) {
872 _processed_frames = 0;
873 _measuring_latency = MeasureNone;
874 _latency_output_port = 0;
875 _latency_input_port = 0;
876 _started_for_latency = false;
881 Stopped (); /* EMIT SIGNAL */
888 AudioEngine::freewheel (bool start_stop)
894 /* _freewheeling will be set when first Freewheel signal occurs */
896 return _backend->freewheel (start_stop);
900 AudioEngine::get_dsp_load() const
905 return _backend->dsp_load ();
909 AudioEngine::is_realtime() const
915 return _backend->is_realtime();
919 AudioEngine::connected() const
925 return _backend->available();
929 AudioEngine::transport_start ()
934 return _backend->transport_start ();
938 AudioEngine::transport_stop ()
943 return _backend->transport_stop ();
947 AudioEngine::transport_state ()
950 return TransportStopped;
952 return _backend->transport_state ();
956 AudioEngine::transport_locate (framepos_t pos)
961 return _backend->transport_locate (pos);
965 AudioEngine::transport_frame()
970 return _backend->transport_frame ();
974 AudioEngine::sample_rate () const
979 return _backend->sample_rate ();
983 AudioEngine::samples_per_cycle () const
988 return _backend->buffer_size ();
992 AudioEngine::usecs_per_cycle () const
997 return _backend->usecs_per_cycle ();
1001 AudioEngine::raw_buffer_size (DataType t)
1006 return _backend->raw_buffer_size (t);
1010 AudioEngine::sample_time ()
1015 return _backend->sample_time ();
1019 AudioEngine::sample_time_at_cycle_start ()
1024 return _backend->sample_time_at_cycle_start ();
1028 AudioEngine::samples_since_cycle_start ()
1033 return _backend->samples_since_cycle_start ();
1037 AudioEngine::get_sync_offset (pframes_t& offset) const
1042 return _backend->get_sync_offset (offset);
1046 AudioEngine::create_process_thread (boost::function<void()> func)
1051 return _backend->create_process_thread (func);
1055 AudioEngine::join_process_threads ()
1060 return _backend->join_process_threads ();
1064 AudioEngine::in_process_thread ()
1069 return _backend->in_process_thread ();
1073 AudioEngine::process_thread_count ()
1078 return _backend->process_thread_count ();
1082 AudioEngine::set_device_name (const std::string& name)
1087 return _backend->set_device_name (name);
1091 AudioEngine::set_sample_rate (float sr)
1097 return _backend->set_sample_rate (sr);
1101 AudioEngine::set_buffer_size (uint32_t bufsiz)
1106 return _backend->set_buffer_size (bufsiz);
1110 AudioEngine::set_interleaved (bool yn)
1115 return _backend->set_interleaved (yn);
1119 AudioEngine::set_input_channels (uint32_t ic)
1124 return _backend->set_input_channels (ic);
1128 AudioEngine::set_output_channels (uint32_t oc)
1133 return _backend->set_output_channels (oc);
1137 AudioEngine::set_systemic_input_latency (uint32_t il)
1142 return _backend->set_systemic_input_latency (il);
1146 AudioEngine::set_systemic_output_latency (uint32_t ol)
1151 return _backend->set_systemic_output_latency (ol);
1155 AudioEngine::thread_initialised_for_audio_processing ()
1157 return SessionEvent::has_per_thread_pool () && AsyncMIDIPort::is_process_thread();
1160 /* END OF BACKEND PROXY API */
1163 AudioEngine::thread_init_callback (void* arg)
1165 /* make sure that anybody who needs to know about this thread
1169 pthread_set_name (X_("audioengine"));
1171 SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
1173 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
1174 PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
1176 AsyncMIDIPort::set_process_thread (pthread_self());
1179 /* the special thread created/managed by the backend */
1180 AudioEngine::instance()->_main_thread = new ProcessThread;
1185 AudioEngine::sync_callback (TransportState state, framepos_t position)
1188 return _session->backend_sync_callback (state, position);
1194 AudioEngine::freewheel_callback (bool onoff)
1196 _freewheeling = onoff;
1200 AudioEngine::latency_callback (bool for_playback)
1203 _session->update_latency (for_playback);
1208 AudioEngine::update_latencies ()
1211 _backend->update_latencies ();
1216 AudioEngine::halted_callback (const char* why)
1218 if (_in_destructor) {
1219 /* everything is under control */
1225 Port::PortDrop (); /* EMIT SIGNAL */
1227 if (!_started_for_latency) {
1228 Halted (why); /* EMIT SIGNAL */
1233 AudioEngine::setup_required () const
1236 if (_backend->info().already_configured())
1239 if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
1248 AudioEngine::prepare_for_latency_measurement ()
1251 _stopped_for_latency = true;
1256 _started_for_latency = true;
1264 AudioEngine::start_latency_detection (bool for_midi)
1267 if (prepare_for_latency_measurement ()) {
1272 PortEngine& pe (port_engine());
1280 /* find the ports we will connect to */
1282 PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
1283 PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
1290 /* create the ports we will use to read/write data */
1292 if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, 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::MIDI, 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 _mididm = new MIDIDM (sample_rate());
1320 if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
1324 if (pe.connect (_latency_output_port, _latency_output_name)) {
1325 pe.unregister_port (_latency_output_port);
1330 const string portname ("latency_in");
1331 if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
1332 pe.unregister_port (_latency_input_port);
1333 pe.unregister_port (_latency_output_port);
1337 if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
1338 pe.unregister_port (_latency_input_port);
1339 pe.unregister_port (_latency_output_port);
1344 _mtdm = new MTDM (sample_rate());
1349 _latency_signal_latency = 0;
1350 lr = pe.get_latency_range (in, false);
1351 _latency_signal_latency = lr.max;
1352 lr = pe.get_latency_range (out, true);
1353 _latency_signal_latency += lr.max;
1355 /* all created and connected, lets go */
1356 _latency_flush_frames = samples_per_cycle();
1357 _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
1363 AudioEngine::stop_latency_detection ()
1365 _measuring_latency = MeasureNone;
1367 if (_latency_output_port) {
1368 port_engine().unregister_port (_latency_output_port);
1369 _latency_output_port = 0;
1371 if (_latency_input_port) {
1372 port_engine().unregister_port (_latency_input_port);
1373 _latency_input_port = 0;
1378 if (_stopped_for_latency) {
1382 _stopped_for_latency = false;
1383 _started_for_latency = false;
1387 AudioEngine::set_latency_output_port (const string& name)
1389 _latency_output_name = name;
1393 AudioEngine::set_latency_input_port (const string& name)
1395 _latency_input_name = name;