From 4edb5e0ee7cf9bc153c2b966ff2a60edc2cf5e9f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 15 Apr 2021 04:42:55 +0200 Subject: [PATCH] Towards CoreMIDI systemic latency calibration --- libs/backends/coreaudio/coreaudio_backend.cc | 144 ++++++++++++++++++- libs/backends/coreaudio/coreaudio_backend.h | 41 ++++-- 2 files changed, 168 insertions(+), 17 deletions(-) diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc index 20aeef9ff6..addf736039 100644 --- a/libs/backends/coreaudio/coreaudio_backend.cc +++ b/libs/backends/coreaudio/coreaudio_backend.cc @@ -371,14 +371,26 @@ CoreAudioBackend::set_output_channels (uint32_t cc) int CoreAudioBackend::set_systemic_input_latency (uint32_t sl) { + if (_systemic_audio_input_latency == sl) { + return 0; + } _systemic_audio_input_latency = sl; + if (_run) { + update_systemic_audio_latencies(); + } return 0; } int CoreAudioBackend::set_systemic_output_latency (uint32_t sl) { + if (_systemic_audio_output_latency == sl) { + return 0; + } _systemic_audio_output_latency = sl; + if (_run) { + update_systemic_audio_latencies (); + } return 0; } @@ -489,6 +501,122 @@ CoreAudioBackend::midi_option () const return _midi_driver_option; } +std::vector +CoreAudioBackend::enumerate_midi_devices () const { + std::vector mds; + std::map duplexdevs; + for (size_t i = 0; i < _midiio->n_midi_inputs(); ++i) { + ++duplexdevs[_midiio->port_name(i, true)]; + } + for (size_t i = 0; i < _midiio->n_midi_outputs(); ++i) { + ++duplexdevs[_midiio->port_name(i, false)]; + } + std::map ::iterator i; + for (i = duplexdevs.begin(); i != duplexdevs.end (); ++i) { + if (i->second < 2) { + continue; + } + mds.push_back (AudioBackend::DeviceStatus (i->first, true)); + } + return mds; +} + +int +CoreAudioBackend::set_midi_device_enabled (std::string const n, bool en) +{ + struct CoreMIDIDeviceInfo& nfo = _midi_devices[n]; + if (nfo.enabled == en) { + return true; + } +#if 0 + nfo.enabled = false; + coremidi_rediscover (); +#endif + return true; +} + +bool +CoreAudioBackend::midi_device_enabled (std::string const n) const +{ + return _midi_devices[n].enabled;; +} + +uint32_t +CoreAudioBackend::systemic_midi_input_latency (std::string const n) const +{ + return _midi_devices[n].systemic_input_latency; +} + +uint32_t +CoreAudioBackend::systemic_midi_output_latency (std::string const n) const +{ + return _midi_devices[n].systemic_output_latency; +} + +int +CoreAudioBackend::set_systemic_midi_input_latency (std::string const n, uint32_t l) +{ + struct CoreMIDIDeviceInfo& nfo = _midi_devices[n]; + nfo.systemic_input_latency = l; + //_midi_devices[n].systemic_input_latency = l; + if (_run && nfo.enabled) { + update_systemic_midi_latencies (); + } + return 0; +} + +int +CoreAudioBackend::set_systemic_midi_output_latency (std::string const n, uint32_t l) +{ + struct CoreMIDIDeviceInfo& nfo = _midi_devices[n]; + nfo.systemic_output_latency = l; + //_midi_devices[n].systemic_output_latency = l; + if (_run && nfo.enabled) { + update_systemic_midi_latencies (); + } + return 0; +} + +void +CoreAudioBackend::update_systemic_audio_latencies () +{ + LatencyRange lr; + + lr.min = lr.max = _measure_latency ? 0 : _systemic_audio_input_latency; + for (std::vector::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) { + set_latency_range (*it, true, lr); + } + + lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency); + for (std::vector::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) { + set_latency_range (*it, false, lr); + } + update_latencies (); +} + +void +CoreAudioBackend::update_systemic_midi_latencies () +{ + pthread_mutex_lock (&_process_callback_mutex); + uint32_t i = 0; + for (std::vector::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) { + LatencyRange lr; + uint32_t sl = _midi_devices[_midiio->port_name(i, false)].systemic_output_latency; + lr.min = lr.max = _measure_latency ? 0 : sl; + set_latency_range (*it, true, lr); + } + + i = 0; + for (std::vector::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) { + LatencyRange lr; + uint32_t sl = _midi_devices[_midiio->port_name(i, true)].systemic_input_latency; + lr.min = lr.max = _measure_latency ? 0 : sl; + set_latency_range (*it, false, lr); + } + pthread_mutex_unlock (&_process_callback_mutex); + update_latencies (); +} + void CoreAudioBackend::launch_control_app () { @@ -528,6 +656,13 @@ CoreAudioBackend::_start (bool for_latency_measurement) } if (_active_ca || _active_fw || _run) { + if (for_latency_measurement != _measure_latency) { + _measure_latency = for_latency_measurement; + update_systemic_audio_latencies(); + update_systemic_midi_latencies (); + PBD::info << _("AlsaAudioBackend: reload latencies.") << endmsg; + return NoError; + } PBD::error << _("CoreAudioBackend: already active.") << endmsg; return BackendReinitializationError; } @@ -646,6 +781,7 @@ CoreAudioBackend::_start (bool for_latency_measurement) _midiio->set_enabled(true); _midiio->set_port_changed_callback(midi_port_change, this); _midiio->start(); // triggers port discovery, callback coremidi_rediscover() + engine.request_device_list_update(); } if (register_system_audio_ports()) { @@ -1029,7 +1165,8 @@ CoreAudioBackend::coremidi_rediscover() continue; } LatencyRange lr; - lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency + uint32_t sl = _midi_devices[_midiio->port_name(i, true)].systemic_input_latency; + lr.min = lr.max = _measure_latency ? 0 : sl; set_latency_range (p, false, lr); BackendPortPtr pp = boost::dynamic_pointer_cast(p); pp->set_hw_port_name(_midiio->port_name(i, true)); @@ -1052,8 +1189,9 @@ CoreAudioBackend::coremidi_rediscover() continue; } LatencyRange lr; - lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency - set_latency_range (p, false, lr); + uint32_t sl = _midi_devices[_midiio->port_name(i, false)].systemic_output_latency; + lr.min = lr.max = _measure_latency ? 0 : sl; + set_latency_range (p, true, lr); BackendPortPtr pp = boost::dynamic_pointer_cast(p); pp->set_hw_port_name(_midiio->port_name(i, false)); _system_midi_out.push_back(pp); diff --git a/libs/backends/coreaudio/coreaudio_backend.h b/libs/backends/coreaudio/coreaudio_backend.h index 299853f45b..8fa6d07cf8 100644 --- a/libs/backends/coreaudio/coreaudio_backend.h +++ b/libs/backends/coreaudio/coreaudio_backend.h @@ -179,6 +179,7 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { bool can_change_sample_rate_when_running () const; bool can_change_buffer_size_when_running () const; bool can_measure_systemic_latency () const { return true; } + bool can_change_systemic_latency_when_running () const { return true; } int set_device_name (const std::string&); int set_input_device_name (const std::string&); @@ -190,8 +191,8 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { int set_output_channels (uint32_t); int set_systemic_input_latency (uint32_t); int set_systemic_output_latency (uint32_t); - int set_systemic_midi_input_latency (std::string const, uint32_t) { return 0; } - int set_systemic_midi_output_latency (std::string const, uint32_t) { return 0; } + int set_systemic_midi_input_latency (std::string const, uint32_t); + int set_systemic_midi_output_latency (std::string const, uint32_t); int reset_device () { return 0; }; @@ -206,13 +207,13 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { uint32_t output_channels () const; uint32_t systemic_input_latency () const; uint32_t systemic_output_latency () const; - uint32_t systemic_midi_input_latency (std::string const) const { return 0; } - uint32_t systemic_midi_output_latency (std::string const) const { return 0; } + uint32_t systemic_midi_input_latency (std::string const) const; + uint32_t systemic_midi_output_latency (std::string const) const; uint32_t systemic_hw_input_latency () const; uint32_t systemic_hw_output_latency () const; - bool can_set_systemic_midi_latencies () const { return false; /* XXX */} + bool can_set_systemic_midi_latencies () const { return true; } /* External control app */ std::string control_app_name () const { return std::string ("Apple"); } @@ -223,15 +224,9 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { int set_midi_option (const std::string&); std::string midi_option () const; - std::vector enumerate_midi_devices () const { - return std::vector (); - } - int set_midi_device_enabled (std::string const, bool) { - return true; - } - bool midi_device_enabled (std::string const) const { - return false; - } + std::vector enumerate_midi_devices () const; + int set_midi_device_enabled (std::string const, bool); + bool midi_device_enabled (std::string const) const; // really private, but needing static access: int process_callback(uint32_t, uint64_t); @@ -373,6 +368,21 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { enum DeviceFilter { All, Input, Output, Duplex }; uint32_t name_to_id(std::string, DeviceFilter filter = All) const; + /* midi settings */ + struct CoreMIDIDeviceInfo { + bool enabled; + uint32_t systemic_input_latency; + uint32_t systemic_output_latency; + CoreMIDIDeviceInfo (bool en = true) + : enabled (en) + , systemic_input_latency (0) + , systemic_output_latency (0) + {} + }; + + mutable std::map _midi_devices; + + /* processing */ float _dsp_load; ARDOUR::DSPLoadCalculator _dsp_load_calc; @@ -397,6 +407,9 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { /* port engine */ int register_system_audio_ports (); + void update_systemic_audio_latencies (); + void update_systemic_midi_latencies (); + BackendPortPtr find_port_in (std::vector const & plist, const std::string& port_name) const { for (std::vector::const_iterator it = plist.begin (); it != plist.end (); ++it) { if ((*it)->name () == port_name) {