X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudioengine.cc;h=83919bbe6a17b7d56acd78db318251b9cbc15047;hb=9cf9833a93f5af0700dad44da4864565fa675862;hp=a87a5ee7d0192015a07e17c34a812d6acd255f20;hpb=95f91d9dbd5cbd801c3cb7f0c277fea94f289342;p=ardour.git diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index a87a5ee7d0..83919bbe6a 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -53,9 +53,10 @@ #include "ardour/mtdm.h" #include "ardour/port.h" #include "ardour/process_thread.h" +#include "ardour/rc_configuration.h" #include "ardour/session.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -63,6 +64,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 +77,7 @@ AudioEngine::AudioEngine () , _freewheeling (false) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) - , _processed_frames (0) + , _processed_samples (0) , m_meter_thread (0) , _main_thread (0) , _mtdm (0) @@ -82,18 +85,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) , _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) + , _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) @@ -112,6 +115,7 @@ AudioEngine::~AudioEngine () for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) { i->second->deinstantiate(); } + delete _main_thread; } AudioEngine* @@ -151,7 +155,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 */ @@ -177,7 +181,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"))) @@ -186,19 +190,20 @@ 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; - /* 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()) { @@ -215,6 +220,26 @@ AudioEngine::process_callback (pframes_t 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) { @@ -262,7 +287,7 @@ 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. @@ -272,11 +297,11 @@ AudioEngine::process_callback (pframes_t 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; } @@ -324,48 +349,72 @@ AudioEngine::process_callback (pframes_t nframes) 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()) { + // TODO: Run a list of slaves here + // - multiple TC slaves (how_many_dsp_threads() in parallel) + // (note this can be multiple slaves of each type. e.g. + // 3 LTC slaves on different ports, 2 MTC..) + // - GUI can display all slaves, user picks one. + // - active "slave" is a session property. + // - here we ask the session about the active slave + // and get playback speed (for this cycle) here. + // - Internal Transport is-a Slave too (!) + Port::set_speed_ratio (_session->engine_speed ()); // HACK + } + /* 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 @@ -389,13 +438,13 @@ AudioEngine::process_callback (pframes_t nframes) #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; @@ -404,11 +453,11 @@ 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); @@ -442,9 +491,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 @@ -469,28 +518,28 @@ AudioEngine::do_reset_backend() 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 + 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 (); + // backup the device name + std::string name = _backend->device_name (); - std::cout << "AudioEngine::RESET::Reseting device..." << std::endl; + 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 + DeviceResetFinished(); // notify about device reset finish - } else { + } else { - DeviceResetFinished(); // notify about device reset finish + DeviceResetFinished(); // notify about device reset finish // we've got an error - DeviceError(); + DeviceError(); } std::cout << "AudioEngine::RESET::Done." << std::endl; @@ -504,81 +553,79 @@ AudioEngine::do_reset_backend() } } } + 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); + SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512); - Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); + Glib::Threads::Mutex::Lock guard (_devicelist_update_lock); - while (!_stop_hw_devicelist_processing) { + while (!_stop_hw_devicelist_processing) { - if (_hw_devicelist_update_count) { + if (_hw_devicelist_update_count) { - _devicelist_update_lock.unlock(); + _devicelist_update_lock.unlock(); - Glib::Threads::RecMutex::Lock pl (_state_lock); + Glib::Threads::RecMutex::Lock pl (_state_lock); - g_atomic_int_dec_and_test (&_hw_devicelist_update_count); - DeviceListChanged (); /* EMIT SIGNAL */ + g_atomic_int_dec_and_test (&_hw_devicelist_update_count); + DeviceListChanged (); /* EMIT SIGNAL */ - _devicelist_update_lock.lock(); + _devicelist_update_lock.lock(); - } else { - _hw_devicelist_update_condition.wait (_devicelist_update_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_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_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) { @@ -752,12 +799,26 @@ AudioEngine::backend_discover (const string& path) 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); } @@ -835,21 +896,20 @@ AudioEngine::start (bool for_latency) return 0; } - _processed_frames = 0; + _processed_samples = 0; last_monitor_check = 0; int error_code = _backend->start (for_latency); if (error_code != 0) { - _last_backend_error_string = - AudioBackend::get_error_string((AudioBackend::ErrorCode)error_code); + _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); @@ -857,6 +917,10 @@ AudioEngine::start (bool for_latency) } + /* XXX MIDI ports may not actually be available here yet .. */ + + PortManager::fill_midi_port_info (); + if (!for_latency) { Running(); /* EMIT SIGNAL */ } @@ -881,9 +945,14 @@ AudioEngine::stop (bool for_latency) 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 ()) { - pl.release (); + if (pl.locked ()) { + pl.release (); + } return -1; } } @@ -900,20 +969,24 @@ AudioEngine::stop (bool for_latency) _session->engine_halted (); } - if (stop_engine) { + if (stop_engine && _running) { _running = false; + if (!for_latency) { + _started_for_latency = false; + } else if (!_started_for_latency) { + _stopped_for_latency = true; + } } - _processed_frames = 0; + _processed_samples = 0; _measuring_latency = MeasureNone; _latency_output_port = 0; _latency_input_port = 0; - _started_for_latency = false; if (stop_engine) { Port::PortDrop (); } - if (!for_latency && stop_engine) { + if (stop_engine) { Stopped (); /* EMIT SIGNAL */ } @@ -989,7 +1062,7 @@ AudioEngine::transport_state () } void -AudioEngine::transport_locate (framepos_t pos) +AudioEngine::transport_locate (samplepos_t pos) { if (!_backend) { return; @@ -997,16 +1070,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) { @@ -1042,7 +1115,7 @@ AudioEngine::raw_buffer_size (DataType t) return _backend->raw_buffer_size (t); } -framepos_t +samplepos_t AudioEngine::sample_time () { if (!_backend) { @@ -1051,7 +1124,7 @@ AudioEngine::sample_time () return _backend->sample_time (); } -framepos_t +samplepos_t AudioEngine::sample_time_at_cycle_start () { if (!_backend) { @@ -1190,7 +1263,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 */ @@ -1204,21 +1277,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); @@ -1235,9 +1309,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 @@ -1287,17 +1361,21 @@ AudioEngine::prepare_for_latency_measurement () return -1; } + if (running() && _started_for_latency) { + return 0; + } + if (_backend->can_change_systemic_latency_when_running()) { - if (start()) { + if (_running) { + _backend->start (true); // zero latency reporting of running backend + } else if (start (true)) { return -1; } - _backend->set_systemic_input_latency (0); - _backend->set_systemic_output_latency (0); + _started_for_latency = true; return 0; } if (running()) { - _stopped_for_latency = true; stop (true); } @@ -1305,7 +1383,6 @@ AudioEngine::prepare_for_latency_measurement () return -1; } _started_for_latency = true; - return 0; } @@ -1400,7 +1477,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; @@ -1420,6 +1497,18 @@ AudioEngine::stop_latency_detection () _latency_input_port = 0; } + 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); } @@ -1443,3 +1532,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; + } +}