X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudioengine.cc;h=0b01f97f7a2ab4cdca473ea2566d32505097d212;hb=cd8aa4e3044bfa2f6956e02ccc5458b3c9fbadc4;hp=09478e7ef7bad6bc5bb58964a41b9b410dea26a9;hpb=676ff806970925972b165cd7621ba7ea8c82c08a;p=ardour.git diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 09478e7ef7..0b01f97f7a 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -34,8 +34,6 @@ #include "pbd/stacktrace.h" #include "pbd/unknown_type.h" -#include - #include "midi++/port.h" #include "midi++/mmc.h" @@ -43,7 +41,7 @@ #include "ardour/audio_port.h" #include "ardour/audio_backend.h" #include "ardour/audioengine.h" -#include "ardour/backend_search_path.h" +#include "ardour/search_paths.h" #include "ardour/buffer.h" #include "ardour/cycle_timer.h" #include "ardour/internal_send.h" @@ -79,6 +77,9 @@ AudioEngine::AudioEngine () , _latency_input_port (0) , _latency_output_port (0) , _latency_flush_frames (0) + , _latency_signal_latency (0) + , _stopped_for_latency (false) + , _in_destructor (false) { g_atomic_int_set (&m_meter_exit, 0); discover_backends (); @@ -86,15 +87,9 @@ AudioEngine::AudioEngine () AudioEngine::~AudioEngine () { + _in_destructor = true; + stop_metering_thread (); drop_backend (); - - config_connection.disconnect (); - - { - Glib::Threads::Mutex::Lock tm (_process_lock); - session_removed.signal (); - stop_metering_thread (); - } } AudioEngine* @@ -198,11 +193,18 @@ AudioEngine::process_callback (pframes_t nframes) return 0; } - /* If measuring latency, do it now and get out of here */ + bool return_after_remove_check = false; if (_measuring_latency && _mtdm) { - // PortManager::cycle_start (nframes); - // PortManager::silence (nframes); + /* run a normal cycle from the perspective of the PortManager + so that we get silence on all registered ports. + + we overwrite the silence on the two ports used for latency + measurement. + */ + + PortManager::cycle_start (nframes); + PortManager::silence (nframes); if (_latency_input_port && _latency_output_port) { PortEngine& pe (port_engine()); @@ -213,8 +215,8 @@ AudioEngine::process_callback (pframes_t nframes) _mtdm->process (nframes, in, out); } - // PortManager::cycle_end (nframes); - return 0; + PortManager::cycle_end (nframes); + return_after_remove_check = true; } else if (_latency_flush_frames) { @@ -232,7 +234,7 @@ AudioEngine::process_callback (pframes_t nframes) _latency_flush_frames = 0; } - return 0; + return_after_remove_check = true; } if (session_remove_pending) { @@ -271,6 +273,10 @@ AudioEngine::process_callback (pframes_t nframes) } } + if (return_after_remove_check) { + return 0; + } + if (_session == 0) { if (!_freewheeling) { @@ -412,8 +418,6 @@ AudioEngine::remove_session () if (_running) { - stop_metering_thread (); - if (_session) { session_remove_pending = true; session_removal_countdown = 0; @@ -469,23 +473,40 @@ AudioEngine::discover_backends () Glib::PatternSpec so_extension_pattern("*backend.so"); Glib::PatternSpec dylib_extension_pattern("*backend.dylib"); +#if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS) + #if defined(DEBUG) || defined(_DEBUG) + Glib::PatternSpec dll_extension_pattern("*backendD.dll"); + #else + Glib::PatternSpec dll_extension_pattern("*backendRDC.dll"); + #endif +#else + Glib::PatternSpec dll_extension_pattern("*backend.dll"); +#endif + find_matching_files_in_search_path (backend_search_path (), so_extension_pattern, backend_modules); find_matching_files_in_search_path (backend_search_path (), dylib_extension_pattern, backend_modules); - DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1\n"), backend_search_path().to_string())); + find_matching_files_in_search_path (backend_search_path (), + dll_extension_pattern, backend_modules); + + DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string())); for (vector::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { AudioBackendInfo* info; + DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i)); + if ((info = backend_discover (*i)) != 0) { _backends.insert (make_pair (info->name, info)); } } + DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size())); + return _backends.size(); } @@ -494,7 +515,8 @@ AudioEngine::backend_discover (const string& path) { Glib::Module module (path); AudioBackendInfo* info; - void* sym = 0; + AudioBackendInfo* (*dfunc)(void); + void* func = 0; if (!module) { error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, @@ -502,15 +524,16 @@ AudioEngine::backend_discover (const string& path) return 0; } - if (!module.get_symbol ("descriptor", sym)) { - error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor."), path) << endmsg; + if (!module.get_symbol ("descriptor", func)) { + error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg; error << Glib::Module::get_last_error() << endmsg; return 0; } module.make_resident (); - info = (AudioBackendInfo*) sym; + dfunc = (AudioBackendInfo* (*)(void))func; + info = dfunc(); return info; } @@ -541,10 +564,21 @@ AudioEngine::drop_backend () { if (_backend) { _backend->stop (); + _backend->drop_device(); _backend.reset (); } } +boost::shared_ptr +AudioEngine::set_default_backend () +{ + if (_backends.empty()) { + return boost::shared_ptr(); + } + + return set_backend (_backends.begin()->first, "", ""); +} + boost::shared_ptr AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2) { @@ -561,8 +595,7 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons throw failed_constructor (); } - _backend = b->second->backend_factory (*this); - _impl = b->second->portengine_factory (*this); + _backend = b->second->factory (*this); } catch (exception& e) { error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg; @@ -575,7 +608,7 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons /* BACKEND PROXY WRAPPERS */ int -AudioEngine::start () +AudioEngine::start (bool for_latency) { if (!_backend) { return -1; @@ -588,7 +621,7 @@ AudioEngine::start () _processed_frames = 0; last_monitor_check = 0; - if (_backend->start()) { + if (_backend->start (for_latency)) { return -1; } @@ -604,13 +637,15 @@ AudioEngine::start () start_metering_thread (); - Running(); /* EMIT SIGNAL */ + if (!for_latency) { + Running(); /* EMIT SIGNAL */ + } return 0; } int -AudioEngine::stop () +AudioEngine::stop (bool for_latency) { if (!_backend) { return 0; @@ -627,28 +662,15 @@ AudioEngine::stop () _measuring_latency = false; _latency_output_port = 0; _latency_input_port = 0; + _started_for_latency = false; stop_metering_thread (); Port::PortDrop (); - Stopped (); /* EMIT SIGNAL */ - - return 0; -} -int -AudioEngine::pause () -{ - if (!_backend) { - return 0; + if (!for_latency) { + Stopped (); /* EMIT SIGNAL */ } - if (_backend->pause ()) { - return -1; - } - - _running = false; - - Stopped(); /* EMIT SIGNAL */ return 0; } @@ -665,12 +687,12 @@ AudioEngine::freewheel (bool start_stop) } float -AudioEngine::get_cpu_load() const +AudioEngine::get_dsp_load() const { if (!_backend) { return 0.0; } - return _backend->cpu_load (); + return _backend->dsp_load (); } bool @@ -690,7 +712,7 @@ AudioEngine::connected() const return false; } - return _backend->connected(); + return _backend->available(); } void @@ -811,49 +833,66 @@ AudioEngine::get_sync_offset (pframes_t& offset) const } int -AudioEngine::create_process_thread (boost::function func, pthread_t* thr, size_t stacksize) +AudioEngine::create_process_thread (boost::function func) { if (!_backend) { return -1; } - return _backend->create_process_thread (func, thr, stacksize); + return _backend->create_process_thread (func); } - int -AudioEngine::set_device_name (const std::string& name) +AudioEngine::join_process_threads () { if (!_backend) { return -1; } - return _backend->set_device_name (name); + return _backend->join_process_threads (); +} + +bool +AudioEngine::in_process_thread () +{ + if (!_backend) { + return false; + } + return _backend->in_process_thread (); +} + +uint32_t +AudioEngine::process_thread_count () +{ + if (!_backend) { + return 0; + } + return _backend->process_thread_count (); } int -AudioEngine::set_sample_rate (float sr) +AudioEngine::set_device_name (const std::string& name) { if (!_backend) { return -1; } - return _backend->set_sample_rate (sr); + return _backend->set_device_name (name); } int -AudioEngine::set_buffer_size (uint32_t bufsiz) +AudioEngine::set_sample_rate (float sr) { if (!_backend) { return -1; } - return _backend->set_buffer_size (bufsiz); + return _backend->set_sample_rate (sr); } int -AudioEngine::set_sample_format (SampleFormat sf) +AudioEngine::set_buffer_size (uint32_t bufsiz) { if (!_backend) { return -1; } - return _backend->set_sample_format (sf); + return _backend->set_buffer_size (bufsiz); } int @@ -959,16 +998,31 @@ AudioEngine::update_latencies () void AudioEngine::halted_callback (const char* why) { + if (_in_destructor) { + /* everything is under control */ + return; + } + stop_metering_thread (); _running = false; Port::PortDrop (); /* EMIT SIGNAL */ - Halted (why); /* EMIT SIGNAL */ + + if (!_started_for_latency) { + Halted (why); /* EMIT SIGNAL */ + } } bool AudioEngine::setup_required () const { + /* If there is only a single backend and it claims to be configured + * already there is no setup to be done. + * + * Primarily for a case where there is only a JACK backend and + * JACK is already running. + */ + if (_backends.size() == 1 && _backends.begin()->second->already_configured()) { return false; } @@ -982,35 +1036,118 @@ AudioEngine::mtdm() return _mtdm; } -void +int +AudioEngine::prepare_for_latency_measurement () +{ + if (running()) { + _stopped_for_latency = true; + stop (true); + } + + if (start (true)) { + _started_for_latency = true; + return -1; + } + + return 0; +} + +int AudioEngine::start_latency_detection () { + if (!running()) { + if (prepare_for_latency_measurement ()) { + return -1; + } + } + + PortEngine& pe (port_engine()); + delete _mtdm; + _mtdm = 0; + + /* find the ports we will connect to */ + + PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name); + PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name); + + if (!out || !in) { + stop (true); + return -1; + } + + /* create the ports we will use to read/write data */ + + if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) { + stop (true); + return -1; + } + if (pe.connect (_latency_output_port, _latency_output_name)) { + pe.unregister_port (_latency_output_port); + stop (true); + return -1; + } + + const string portname ("latency_in"); + if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) { + pe.unregister_port (_latency_output_port); + stop (true); + return -1; + } + if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) { + pe.unregister_port (_latency_output_port); + stop (true); + return -1; + } + + LatencyRange lr; + _latency_signal_latency = 0; + lr = pe.get_latency_range (in, false); + _latency_signal_latency = lr.max; + lr = pe.get_latency_range (out, true); + _latency_signal_latency += lr.max; + + /* all created and connected, lets go */ _mtdm = new MTDM (sample_rate()); _measuring_latency = true; _latency_flush_frames = samples_per_cycle(); + + return 0; } void AudioEngine::stop_latency_detection () { - port_engine().unregister_port (_latency_output_port); - port_engine().unregister_port (_latency_input_port); _measuring_latency = false; + + if (_latency_output_port) { + port_engine().unregister_port (_latency_output_port); + _latency_output_port = 0; + } + if (_latency_input_port) { + port_engine().unregister_port (_latency_input_port); + _latency_input_port = 0; + } + + stop (true); + + if (_stopped_for_latency) { + start (); + } + + _stopped_for_latency = false; + _started_for_latency = false; } void AudioEngine::set_latency_output_port (const string& name) { - _latency_output_port = port_engine().register_port ("latency_out", DataType::AUDIO, IsOutput); - port_engine().connect (_latency_output_port, name); + _latency_output_name = name; } void AudioEngine::set_latency_input_port (const string& name) { - const string portname ("latency_in"); - _latency_input_port = port_engine().register_port (portname, DataType::AUDIO, IsInput); - port_engine().connect (name, make_port_name_non_relative (portname)); + _latency_input_name = name; }