X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudioengine.cc;h=91f58d44adfd0ee299b49df7de5338456d9821d2;hb=32b73439275dbe2cccaa2a71026a951ea46d24b9;hp=16283d92320a145ae360dbc1a548f12790c86709;hpb=6584a89c4eb5024fe89a15acd8e4fa4697e606be;p=ardour.git diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 16283d9232..91f58d44ad 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -53,9 +53,11 @@ #include "ardour/mtdm.h" #include "ardour/port.h" #include "ardour/process_thread.h" +#include "ardour/rc_configuration.h" #include "ardour/session.h" +#include "ardour/transport_master_manager.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -63,6 +65,8 @@ using namespace PBD; AudioEngine* AudioEngine::_instance = 0; +static gint audioengine_thread_cnt = 1; + #ifdef SILENCE_AFTER #define SILENCE_AFTER_SECONDS 600 #endif @@ -74,7 +78,7 @@ AudioEngine::AudioEngine () , _freewheeling (false) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) - , _processed_frames (0) + , _processed_samples (-1) , m_meter_thread (0) , _main_thread (0) , _mtdm (0) @@ -82,17 +86,18 @@ AudioEngine::AudioEngine () , _measuring_latency (MeasureNone) , _latency_input_port (0) , _latency_output_port (0) - , _latency_flush_frames (0) + , _latency_flush_samples (0) , _latency_signal_latency (0) , _stopped_for_latency (false) , _started_for_latency (false) , _in_destructor (false) - , _hw_reset_event_thread(0) - , _hw_reset_request_count(0) - , _stop_hw_reset_processing(0) - , _hw_devicelist_update_thread(0) - , _hw_devicelist_update_count(0) - , _stop_hw_devicelist_processing(0) + , _last_backend_error_string(AudioBackend::get_error_string((AudioBackend::ErrorCode)-1)) + , _hw_reset_event_thread(0) + , _hw_reset_request_count(0) + , _stop_hw_reset_processing(0) + , _hw_devicelist_update_thread(0) + , _hw_devicelist_update_count(0) + , _stop_hw_devicelist_processing(0) #ifdef SILENCE_AFTER_SECONDS , _silence_countdown (0) , _silence_hit_cnt (0) @@ -111,6 +116,7 @@ AudioEngine::~AudioEngine () for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) { i->second->deinstantiate(); } + delete _main_thread; } AudioEngine* @@ -121,7 +127,7 @@ AudioEngine::create () } _instance = new AudioEngine (); - + return _instance; } @@ -150,7 +156,7 @@ AudioEngine::sample_rate_change (pframes_t nframes) last_monitor_check = 0; if (_session) { - _session->set_frame_rate (nframes); + _session->set_sample_rate (nframes); } SampleRateChanged (nframes); /* EMIT SIGNAL */ @@ -158,11 +164,11 @@ AudioEngine::sample_rate_change (pframes_t nframes) #ifdef SILENCE_AFTER_SECONDS _silence_countdown = nframes * SILENCE_AFTER_SECONDS; #endif - + return 0; } -int +int AudioEngine::buffer_size_change (pframes_t bufsiz) { if (_session) { @@ -176,7 +182,7 @@ AudioEngine::buffer_size_change (pframes_t bufsiz) } /** Method called by our ::process_thread when there is work to be done. - * @param nframes Number of frames to process. + * @param nframes Number of samples to process. */ #ifdef __clang__ __attribute__((annotate("realtime"))) @@ -185,19 +191,25 @@ int AudioEngine::process_callback (pframes_t nframes) { Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK); + Port::set_speed_ratio (1.0); PT_TIMING_REF; PT_TIMING_CHECK (1); - /// The number of frames that will have been processed when we've finished - pframes_t next_processed_frames; + /// The number of samples that will have been processed when we've finished + pframes_t next_processed_samples; + + if (_processed_samples < 0) { + _processed_samples = sample_time(); + cerr << "IIIIINIT PS to " << _processed_samples << endl; + } - /* handle wrap around of total frames counter */ + /* handle wrap around of total samples counter */ - if (max_framepos - _processed_frames < nframes) { - next_processed_frames = nframes - (max_framepos - _processed_frames); + if (max_samplepos - _processed_samples < nframes) { + next_processed_samples = nframes - (max_samplepos - _processed_samples); } else { - next_processed_frames = _processed_frames + nframes; + next_processed_samples = _processed_samples + nframes; } if (!tm.locked()) { @@ -207,23 +219,43 @@ AudioEngine::process_callback (pframes_t nframes) } /* really only JACK requires this * (other backends clear the output buffers - * before the process_callback. it may even be + * before the process_callback. it may even be * jack/alsa only). but better safe than sorry. */ PortManager::silence_outputs (nframes); return 0; } + /* The coreaudio-backend calls thread_init_callback() if + * the hardware changes or pthread_self() changes. + * + * However there are cases when neither holds true, yet + * the thread-pool changes: e.g. connect a headphone to + * a shared mic/headphone jack. + * It's probably related to, or caused by clocksource changes. + * + * For reasons yet unknown Glib::Threads::Private() can + * use a different thread-private in the same pthread + * (coreaudio render callback). + * + * Coreaudio must set something which influences + * pthread_key_t uniqness or reset the key using + * pthread_getspecific(). + */ + if (! SessionEvent::has_per_thread_pool ()) { + thread_init_callback (NULL); + } + bool return_after_remove_check = false; if (_measuring_latency == MeasureAudio && _mtdm) { /* 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); @@ -261,8 +293,8 @@ AudioEngine::process_callback (pframes_t nframes) PortManager::cycle_end (nframes); return_after_remove_check = true; - } else if (_latency_flush_frames) { - + } else if (_latency_flush_samples) { + /* wait for the appropriate duration for the MTDM signal to * drain from the ports before we revert to normal behaviour. */ @@ -270,12 +302,12 @@ AudioEngine::process_callback (pframes_t nframes) PortManager::cycle_start (nframes); PortManager::silence (nframes); PortManager::cycle_end (nframes); - - if (_latency_flush_frames > nframes) { - _latency_flush_frames -= nframes; - } else { - _latency_flush_frames = 0; - } + + if (_latency_flush_samples > nframes) { + _latency_flush_samples -= nframes; + } else { + _latency_flush_samples = 0; + } return_after_remove_check = true; } @@ -294,12 +326,12 @@ AudioEngine::process_callback (pframes_t nframes) } else if (session_removal_countdown > 0) { /* we'll be fading audio out. - - if this is the last time we do this as part + + if this is the last time we do this as part of session removal, do a MIDI panic now to get MIDI stopped. This relies on the fact that "immediate data" (aka "out of band data") from - MIDI tracks is *appended* after any other data, + MIDI tracks is *appended* after any other data, so that it emerges after any outbound note ons, etc. */ @@ -320,57 +352,82 @@ AudioEngine::process_callback (pframes_t nframes) return 0; } + TransportMasterManager& tmm (TransportMasterManager::instance()); + + /* make sure the TMM is up to date about the current session */ + + if (_session != tmm.session()) { + tmm.set_session (_session); + } + if (_session == 0) { if (!_freewheeling) { - PortManager::cycle_start (nframes); - PortManager::cycle_end (nframes); + PortManager::silence_outputs (nframes); } - _processed_frames = next_processed_frames; + _processed_samples = next_processed_samples; return 0; } + if (!_freewheeling || Freewheel.empty()) { + const double engine_speed = tmm.pre_process_transport_masters (nframes, sample_time_at_cycle_start()); + Port::set_speed_ratio (engine_speed); + DEBUG_TRACE (DEBUG::Slave, string_compose ("transport master (current=%1) gives speed %2 (ports using %3)\n", tmm.current() ? tmm.current()->name() : string("[]"), engine_speed, Port::speed_ratio())); + } + /* tell all relevant objects that we're starting a new cycle */ InternalSend::CycleStart (nframes); /* tell all Ports that we're starting a new cycle */ - PortManager::cycle_start (nframes); + PortManager::cycle_start (nframes, _session); /* test if we are freewheeling and there are freewheel signals connected. - ardour should act normally even when freewheeling unless /it/ is - exporting (which is what Freewheel.empty() tests for). - */ + * ardour should act normally even when freewheeling unless /it/ is + * exporting (which is what Freewheel.empty() tests for). + */ if (_freewheeling && !Freewheel.empty()) { Freewheel (nframes); } else { - _session->process (nframes); + if (Port::cycle_nframes () <= nframes) { + _session->process (Port::cycle_nframes ()); + } else { + pframes_t remain = Port::cycle_nframes (); + while (remain > 0) { + pframes_t nf = std::min (remain, nframes); + _session->process (nf); + remain -= nf; + if (remain > 0) { + split_cycle (nf); + } + } + } } if (_freewheeling) { - PortManager::cycle_end (nframes); + PortManager::cycle_end (nframes, _session); return 0; } if (!_running) { - _processed_frames = next_processed_frames; + _processed_samples = next_processed_samples; return 0; } - if (last_monitor_check + monitor_check_interval < next_processed_frames) { - + if (last_monitor_check + monitor_check_interval < next_processed_samples) { + PortManager::check_monitoring (); - last_monitor_check = next_processed_frames; + last_monitor_check = next_processed_samples; } #ifdef SILENCE_AFTER_SECONDS bool was_silent = (_silence_countdown == 0); - + if (_silence_countdown >= nframes) { _silence_countdown -= nframes; } else { @@ -385,17 +442,17 @@ AudioEngine::process_callback (pframes_t nframes) if (_silence_countdown == 0 || _session->silent()) { PortManager::silence (nframes); } - -#else + +#else if (_session->silent()) { - PortManager::silence (nframes); + PortManager::silence (nframes, _session); } #endif - + if (session_remove_pending && session_removal_countdown) { - PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes); - + PortManager::cycle_end_fade_out (session_removal_gain, session_removal_gain_step, nframes, _session); + if (session_removal_countdown > nframes) { session_removal_countdown -= nframes; } else { @@ -403,14 +460,14 @@ AudioEngine::process_callback (pframes_t nframes) } session_removal_gain -= (nframes * session_removal_gain_step); + } else { + PortManager::cycle_end (nframes, _session); } - PortManager::cycle_end (nframes); - - _processed_frames = next_processed_frames; + _processed_samples = next_processed_samples; PT_TIMING_CHECK (2); - + return 0; } @@ -441,9 +498,9 @@ AudioEngine::launch_device_control_app() void AudioEngine::request_backend_reset() { - Glib::Threads::Mutex::Lock guard (_reset_request_lock); - g_atomic_int_inc (&_hw_reset_request_count); - _hw_reset_condition.signal (); + Glib::Threads::Mutex::Lock guard (_reset_request_lock); + g_atomic_int_inc (&_hw_reset_request_count); + _hw_reset_condition.signal (); } int @@ -456,127 +513,125 @@ void AudioEngine::do_reset_backend() { SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 1024); - + Glib::Threads::Mutex::Lock guard (_reset_request_lock); - + while (!_stop_hw_reset_processing) { - + if (g_atomic_int_get (&_hw_reset_request_count) != 0 && _backend) { - + _reset_request_lock.unlock(); - + Glib::Threads::RecMutex::Lock pl (_state_lock); g_atomic_int_dec_and_test (&_hw_reset_request_count); - - std::cout << "AudioEngine::RESET::Reset request processing. Requests left: " << _hw_reset_request_count << std::endl; - DeviceResetStarted(); // notify about device reset to be started - - // backup the device name - std::string name = _backend->device_name (); - - std::cout << "AudioEngine::RESET::Reseting device..." << std::endl; + + std::cout << "AudioEngine::RESET::Reset request processing. Requests left: " << _hw_reset_request_count << std::endl; + DeviceResetStarted(); // notify about device reset to be started + + // backup the device name + std::string name = _backend->device_name (); + + std::cout << "AudioEngine::RESET::Reseting device..." << std::endl; if ( ( 0 == stop () ) && - ( 0 == _backend->reset_device () ) && - ( 0 == start () ) ) { - + ( 0 == _backend->reset_device () ) && + ( 0 == start () ) ) { + std::cout << "AudioEngine::RESET::Engine started..." << std::endl; - + // inform about possible changes BufferSizeChanged (_backend->buffer_size() ); - DeviceResetFinished(); // notify about device reset finish - - } else { - - DeviceResetFinished(); // notify about device reset finish + DeviceResetFinished(); // notify about device reset finish + + } else { + + DeviceResetFinished(); // notify about device reset finish // we've got an error - DeviceError(); + DeviceError(); } - + std::cout << "AudioEngine::RESET::Done." << std::endl; _reset_request_lock.lock(); - + } else { - + _hw_reset_condition.wait (_reset_request_lock); - + } } } + void AudioEngine::request_device_list_update() { - Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); - g_atomic_int_inc (&_hw_devicelist_update_count); - _hw_devicelist_update_condition.signal (); + Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); + g_atomic_int_inc (&_hw_devicelist_update_count); + _hw_devicelist_update_condition.signal (); } - void AudioEngine::do_devicelist_update() { - SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512); - - Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); - - while (!_stop_hw_devicelist_processing) { - - if (_hw_devicelist_update_count) { - - _devicelist_update_lock.unlock(); - - Glib::Threads::RecMutex::Lock pl (_state_lock); - - g_atomic_int_dec_and_test (&_hw_devicelist_update_count); - DeviceListChanged (); /* EMIT SIGNAL */ - - _devicelist_update_lock.lock(); - - } else { - _hw_devicelist_update_condition.wait (_devicelist_update_lock); - } - } + SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512); + + Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); + + while (!_stop_hw_devicelist_processing) { + + if (_hw_devicelist_update_count) { + + _devicelist_update_lock.unlock(); + + Glib::Threads::RecMutex::Lock pl (_state_lock); + + g_atomic_int_dec_and_test (&_hw_devicelist_update_count); + DeviceListChanged (); /* EMIT SIGNAL */ + + _devicelist_update_lock.lock(); + + } else { + _hw_devicelist_update_condition.wait (_devicelist_update_lock); + } + } } void AudioEngine::start_hw_event_processing() -{ - if (_hw_reset_event_thread == 0) { - g_atomic_int_set(&_hw_reset_request_count, 0); - g_atomic_int_set(&_stop_hw_reset_processing, 0); - _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this)); - } - - if (_hw_devicelist_update_thread == 0) { - g_atomic_int_set(&_hw_devicelist_update_count, 0); - g_atomic_int_set(&_stop_hw_devicelist_processing, 0); - _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this)); - } +{ + if (_hw_reset_event_thread == 0) { + g_atomic_int_set(&_hw_reset_request_count, 0); + g_atomic_int_set(&_stop_hw_reset_processing, 0); + _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this)); + } + + if (_hw_devicelist_update_thread == 0) { + g_atomic_int_set(&_hw_devicelist_update_count, 0); + g_atomic_int_set(&_stop_hw_devicelist_processing, 0); + _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this)); + } } void AudioEngine::stop_hw_event_processing() { - if (_hw_reset_event_thread) { - g_atomic_int_set(&_stop_hw_reset_processing, 1); - g_atomic_int_set(&_hw_reset_request_count, 0); - _hw_reset_condition.signal (); - _hw_reset_event_thread->join (); - _hw_reset_event_thread = 0; - } - - if (_hw_devicelist_update_thread) { - g_atomic_int_set(&_stop_hw_devicelist_processing, 1); - g_atomic_int_set(&_hw_devicelist_update_count, 0); - _hw_devicelist_update_condition.signal (); - _hw_devicelist_update_thread->join (); - _hw_devicelist_update_thread = 0; - } - -} + if (_hw_reset_event_thread) { + g_atomic_int_set(&_stop_hw_reset_processing, 1); + g_atomic_int_set(&_hw_reset_request_count, 0); + _hw_reset_condition.signal (); + _hw_reset_event_thread->join (); + _hw_reset_event_thread = 0; + } + if (_hw_devicelist_update_thread) { + g_atomic_int_set(&_stop_hw_devicelist_processing, 1); + g_atomic_int_set(&_hw_devicelist_update_count, 0); + _hw_devicelist_update_condition.signal (); + _hw_devicelist_update_thread->join (); + _hw_devicelist_update_thread = 0; + } +} void AudioEngine::set_session (Session *s) @@ -613,7 +668,8 @@ AudioEngine::remove_session () if (_session) { session_remove_pending = true; - session_removal_countdown = 0; + /* signal the start of the fade out countdown */ + session_removal_countdown = -1; session_removed.wait(_process_lock); } @@ -632,7 +688,7 @@ AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_out if (_session) { _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs); } -#endif +#endif } @@ -732,13 +788,13 @@ AudioEngine::backend_discover (const string& path) Glib::Module::get_last_error()) << endmsg; return 0; } - + 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; } - + dfunc = (AudioBackendInfo* (*)(void))func; info = dfunc(); if (!info->available()) { @@ -746,16 +802,30 @@ AudioEngine::backend_discover (const string& path) } module.make_resident (); - + return info; } +#ifdef NDEBUG +static bool running_from_source_tree () +{ + // dup ARDOUR_UI_UTILS::running_from_source_tree () + gchar const *x = g_getenv ("ARDOUR_THEMES_PATH"); + return x && (string (x).find ("gtk2_ardour") != string::npos); +} +#endif + vector AudioEngine::available_backends() const { vector r; - + for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) { +#ifdef NDEBUG + if (i->first == "None (Dummy)" && !running_from_source_tree () && Config->get_hide_dummy_backend ()) { + continue; + } +#endif r.push_back (i->second); } @@ -767,7 +837,7 @@ AudioEngine::current_backend_name() const { if (_backend) { return _backend->name(); - } + } return string(); } @@ -776,6 +846,8 @@ AudioEngine::drop_backend () { if (_backend) { _backend->stop (); + // Stopped is needed for Graph to explicitly terminate threads + Stopped (); /* EMIT SIGNAL */ _backend->drop_device (); _backend.reset (); _running = false; @@ -802,12 +874,12 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons } drop_backend (); - + try { if (b->second->instantiate (arg1, arg2)) { throw failed_constructor (); } - + _backend = b->second->factory (*this); } catch (exception& e) { @@ -831,43 +903,72 @@ AudioEngine::start (bool for_latency) return 0; } - _processed_frames = 0; + _processed_samples = 0; last_monitor_check = 0; - - if (_backend->start (for_latency)) { + + int error_code = _backend->start (for_latency); + + if (error_code != 0) { + _last_backend_error_string = AudioBackend::get_error_string((AudioBackend::ErrorCode) error_code); return -1; } _running = true; - + if (_session) { - _session->set_frame_rate (_backend->sample_rate()); - + _session->set_sample_rate (_backend->sample_rate()); + if (_session->config.get_jack_time_master()) { _backend->set_time_master (true); } } - + + /* XXX MIDI ports may not actually be available here yet .. */ + + PortManager::fill_midi_port_info (); + if (!for_latency) { Running(); /* EMIT SIGNAL */ } - + return 0; } int AudioEngine::stop (bool for_latency) { + bool stop_engine = true; + if (!_backend) { return 0; } - if (_backend->stop ()) { - return -1; + Glib::Threads::Mutex::Lock pl (_process_lock, Glib::Threads::NOT_LOCK); + + if (running()) { + pl.acquire (); + } + + if (for_latency && _backend->can_change_systemic_latency_when_running()) { + stop_engine = false; + if (_running) { + _backend->start (false); // keep running, reload latencies + } + } else { + if (_backend->stop ()) { + if (pl.locked ()) { + pl.release (); + } + return -1; + } + } + + if (pl.locked ()) { + pl.release (); } - - if (_session && _running && + + if (_session && _running && stop_engine && (_session->state_of_the_state() & Session::Loading) == 0 && (_session->state_of_the_state() & Session::Deletion) == 0) { // it's not a halt, but should be handled the same way: @@ -875,19 +976,27 @@ AudioEngine::stop (bool for_latency) _session->engine_halted (); } - _running = false; - _processed_frames = 0; + if (stop_engine && _running) { + _running = false; + if (!for_latency) { + _started_for_latency = false; + } else if (!_started_for_latency) { + _stopped_for_latency = true; + } + } + _processed_samples = 0; _measuring_latency = MeasureNone; _latency_output_port = 0; _latency_input_port = 0; - _started_for_latency = false; - - Port::PortDrop (); - if (!for_latency) { + if (stop_engine) { + Port::PortDrop (); + } + + if (stop_engine) { Stopped (); /* EMIT SIGNAL */ } - + return 0; } @@ -904,16 +1013,16 @@ AudioEngine::freewheel (bool start_stop) } float -AudioEngine::get_dsp_load() const +AudioEngine::get_dsp_load() const { - if (!_backend) { + if (!_backend || !_running) { return 0.0; } return _backend->dsp_load (); } bool -AudioEngine::is_realtime() const +AudioEngine::is_realtime() const { if (!_backend) { return false; @@ -923,7 +1032,7 @@ AudioEngine::is_realtime() const } bool -AudioEngine::connected() const +AudioEngine::connected() const { if (!_backend) { return false; @@ -960,7 +1069,7 @@ AudioEngine::transport_state () } void -AudioEngine::transport_locate (framepos_t pos) +AudioEngine::transport_locate (samplepos_t pos) { if (!_backend) { return; @@ -968,16 +1077,16 @@ AudioEngine::transport_locate (framepos_t pos) return _backend->transport_locate (pos); } -framepos_t -AudioEngine::transport_frame() +samplepos_t +AudioEngine::transport_sample() { if (!_backend) { return 0; } - return _backend->transport_frame (); + return _backend->transport_sample (); } -framecnt_t +samplecnt_t AudioEngine::sample_rate () const { if (!_backend) { @@ -1013,7 +1122,7 @@ AudioEngine::raw_buffer_size (DataType t) return _backend->raw_buffer_size (t); } -framepos_t +samplepos_t AudioEngine::sample_time () { if (!_backend) { @@ -1022,7 +1131,7 @@ AudioEngine::sample_time () return _backend->sample_time (); } -framepos_t +samplepos_t AudioEngine::sample_time_at_cycle_start () { if (!_backend) { @@ -1161,7 +1270,7 @@ AudioEngine::set_systemic_output_latency (uint32_t ol) bool AudioEngine::thread_initialised_for_audio_processing () { - return SessionEvent::has_per_thread_pool () && AsyncMIDIPort::is_process_thread(); + return SessionEvent::has_per_thread_pool () && AsyncMIDIPort::is_process_thread(); } /* END OF BACKEND PROXY API */ @@ -1175,21 +1284,22 @@ AudioEngine::thread_init_callback (void* arg) pthread_set_name (X_("audioengine")); - SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512); - - PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096); - PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128); + const int thread_num = g_atomic_int_add (&audioengine_thread_cnt, 1); + const string thread_name = string_compose (X_("AudioEngine %1"), thread_num); + SessionEvent::create_per_thread_pool (thread_name, 512); + PBD::notify_event_loops_about_thread_creation (pthread_self(), thread_name, 4096); AsyncMIDIPort::set_process_thread (pthread_self()); if (arg) { + delete AudioEngine::instance()->_main_thread; /* the special thread created/managed by the backend */ AudioEngine::instance()->_main_thread = new ProcessThread; } } int -AudioEngine::sync_callback (TransportState state, framepos_t position) +AudioEngine::sync_callback (TransportState state, samplepos_t position) { if (_session) { return _session->backend_sync_callback (state, position); @@ -1206,9 +1316,9 @@ AudioEngine::freewheel_callback (bool onoff) void AudioEngine::latency_callback (bool for_playback) { - if (_session) { - _session->update_latency (for_playback); - } + if (_session) { + _session->update_latency (for_playback); + } } void @@ -1247,33 +1357,47 @@ AudioEngine::setup_required () const return false; } } - + return true; } int AudioEngine::prepare_for_latency_measurement () { + if (!_backend) { + return -1; + } + + if (running() && _started_for_latency) { + return 0; + } + + if (_backend->can_change_systemic_latency_when_running()) { + if (_running) { + _backend->start (true); // zero latency reporting of running backend + } else if (start (true)) { + return -1; + } + _started_for_latency = true; + return 0; + } + if (running()) { - _stopped_for_latency = true; stop (true); } if (start (true)) { - _started_for_latency = true; return -1; } - + _started_for_latency = true; return 0; } int AudioEngine::start_latency_detection (bool for_midi) { - if (!running()) { - if (prepare_for_latency_measurement ()) { - return -1; - } + if (prepare_for_latency_measurement ()) { + return -1; } PortEngine& pe (port_engine()); @@ -1360,7 +1484,7 @@ AudioEngine::start_latency_detection (bool for_midi) _latency_signal_latency += lr.max; /* all created and connected, lets go */ - _latency_flush_frames = samples_per_cycle(); + _latency_flush_samples = samples_per_cycle(); _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio; return 0; @@ -1380,7 +1504,21 @@ AudioEngine::stop_latency_detection () _latency_input_port = 0; } - stop (true); + if (_running && _backend->can_change_systemic_latency_when_running()) { + if (_started_for_latency) { + _running = false; // force reload: reset latencies and emit Running() + start (); + } + } + + if (_running && !_started_for_latency) { + assert (!_stopped_for_latency); + return; + } + + if (!_backend->can_change_systemic_latency_when_running()) { + stop (true); + } if (_stopped_for_latency) { start (); @@ -1401,3 +1539,18 @@ AudioEngine::set_latency_input_port (const string& name) { _latency_input_name = name; } + +void +AudioEngine::add_pending_port_deletion (Port* p) +{ + if (_session) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("adding %1 to pending port deletion list\n", p->name())); + if (_port_deletions_pending.write (&p, 1) != 1) { + error << string_compose (_("programming error: port %1 could not be placed on the pending deletion queue\n"), p->name()) << endmsg; + } + _session->auto_connect_thread_wakeup (); + } else { + DEBUG_TRACE (DEBUG::Ports, string_compose ("Directly delete port %1\n", p->name())); + delete p; + } +}