From: Robin Gareus Date: Fri, 4 Dec 2015 21:19:47 +0000 (+0100) Subject: ALSA: allow to dynamically add/remove midi devices & update their latency. X-Git-Tag: 4.5~296 X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=commitdiff_plain;h=bfd2cbaa3f3d03dbca4c9ad424eab6a2ce4b6e99 ALSA: allow to dynamically add/remove midi devices & update their latency. --- diff --git a/libs/backends/alsa/alsa_audiobackend.cc b/libs/backends/alsa/alsa_audiobackend.cc index 25a5e3f127..8a25f548d7 100644 --- a/libs/backends/alsa/alsa_audiobackend.cc +++ b/libs/backends/alsa/alsa_audiobackend.cc @@ -70,6 +70,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info) , _dsp_load (0) , _processed_samples (0) , _port_change_flag (false) + , _midi_ins (0) + , _midi_outs (0) { _instance_name = s_instance_name; pthread_mutex_init (&_port_callback_mutex, 0); @@ -544,19 +546,27 @@ AlsaAudioBackend::update_systemic_audio_latencies () void AlsaAudioBackend::update_systemic_midi_latencies () { -#if 0 - // TODO, need a way to associate the port with the corresponding AlsaMidiDeviceInfo - for (std::vector::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) { + uint32_t i = 0; + for (std::vector::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) { + assert (_rmidi_out.size() > i); + AlsaMidiOut *rm = _rmidi_out.at(i); + struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name()); + assert (nfo); LatencyRange lr; lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency); set_latency_range (*it, false, lr); } - for (std::vector::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) { + + i = 0; + for (std::vector::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) { + assert (_rmidi_in.size() > i); + AlsaMidiIO *rm = _rmidi_in.at(i); + struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name()); + assert (nfo); LatencyRange lr; lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency); set_latency_range (*it, true, lr); } -#endif update_latencies (); } @@ -712,6 +722,9 @@ AlsaAudioBackend::set_midi_option (const std::string& opt) if (opt != get_standard_device_name(DeviceNone) && opt != _("ALSA raw devices") && opt != _("ALSA sequencer")) { return -1; } + if (_run && _midi_driver_option != opt) { + return -1; + } _midi_driver_option = opt; return 0; } @@ -727,8 +740,41 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable { struct AlsaMidiDeviceInfo * nfo = midi_device_info(device); if (!nfo) return -1; + const bool prev_enabled = nfo->enabled; nfo->enabled = enable; - // TODO - trigger update when already running + + if (_run && prev_enabled != enable) { + if (enable) { + // add ports for the given device + register_system_midi_ports(device); + } else { + // remove all ports provided by the given device + uint32_t i = 0; + for (std::vector::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) { + assert (_rmidi_out.size() > i); + AlsaMidiOut *rm = _rmidi_out.at(i); + if (rm->name () != device) { ++it; ++i; continue; } + it = _system_midi_out.erase (it); + unregister_port (*it); + rm->stop(); + _rmidi_out.erase (_rmidi_out.begin() + i); + delete rm; + } + + i = 0; + for (std::vector::iterator it = _system_midi_in.begin (); it != _system_midi_in.end ();) { + assert (_rmidi_in.size() > i); + AlsaMidiIn *rm = _rmidi_in.at(i); + if (rm->name () != device) { ++it; ++i; continue; } + it = _system_midi_in.erase (it); + unregister_port (*it); + rm->stop(); + _rmidi_in.erase (_rmidi_in.begin() + i); + delete rm; + } + } + update_systemic_midi_latencies (); + } return 0; } @@ -909,6 +955,7 @@ AlsaAudioBackend::_start (bool for_latency_measurement) _measure_latency = for_latency_measurement; + _midi_ins = _midi_outs = 0; register_system_midi_ports(); if (register_system_audio_ports()) { @@ -990,6 +1037,7 @@ AlsaAudioBackend::stop () unregister_ports(); delete _pcmi; _pcmi = 0; + _midi_ins = _midi_outs = 0; release_device(); return (_active == false) ? 0 : -1; @@ -1312,11 +1360,11 @@ AlsaAudioBackend::register_system_audio_ports() } int -AlsaAudioBackend::register_system_midi_ports() +AlsaAudioBackend::register_system_midi_ports(const std::string device) { std::map devices; - int midi_ins = 0; - int midi_outs = 0; + + // TODO use consistent numbering when re-adding devices: _midi_ins, _midi_outs if (_midi_driver_option == get_standard_device_name(DeviceNone)) { return 0; @@ -1327,15 +1375,18 @@ AlsaAudioBackend::register_system_midi_ports() } for (std::map::const_iterator i = devices.begin (); i != devices.end(); ++i) { + if (!device.empty() && device != i->first) { + continue; + } struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first); if (!nfo) continue; if (!nfo->enabled) continue; AlsaMidiOut *mout; if (_midi_driver_option == _("ALSA raw devices")) { - mout = new AlsaRawMidiOut (i->second.c_str()); + mout = new AlsaRawMidiOut (i->first, i->second.c_str()); } else { - mout = new AlsaSeqMidiOut (i->second.c_str()); + mout = new AlsaSeqMidiOut (i->first, i->second.c_str()); } if (mout->state ()) { @@ -1353,7 +1404,7 @@ AlsaAudioBackend::register_system_midi_ports() delete mout; } else { char tmp[64]; - snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins); + snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++_midi_ins); PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast(IsInput | IsPhysical | IsTerminal)); if (!p) { mout->stop(); @@ -1370,9 +1421,9 @@ AlsaAudioBackend::register_system_midi_ports() AlsaMidiIn *midin; if (_midi_driver_option == _("ALSA raw devices")) { - midin = new AlsaRawMidiIn (i->second.c_str()); + midin = new AlsaRawMidiIn (i->first, i->second.c_str()); } else { - midin = new AlsaSeqMidiIn (i->second.c_str()); + midin = new AlsaSeqMidiIn (i->first, i->second.c_str()); } if (midin->state ()) { @@ -1390,7 +1441,7 @@ AlsaAudioBackend::register_system_midi_ports() delete midin; } else { char tmp[64]; - snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++midi_outs); + snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++_midi_outs); PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast(IsOutput | IsPhysical | IsTerminal)); if (!p) { midin->stop(); diff --git a/libs/backends/alsa/alsa_audiobackend.h b/libs/backends/alsa/alsa_audiobackend.h index a661aa2979..2233c9be9e 100644 --- a/libs/backends/alsa/alsa_audiobackend.h +++ b/libs/backends/alsa/alsa_audiobackend.h @@ -395,7 +395,7 @@ class AlsaAudioBackend : public AudioBackend { /* port engine */ PortHandle add_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags); int register_system_audio_ports (); - int register_system_midi_ports (); + int register_system_midi_ports (const std::string device = ""); void unregister_ports (bool system_only = false); std::vector _ports; @@ -407,6 +407,9 @@ class AlsaAudioBackend : public AudioBackend { std::vector _rmidi_out; std::vector _rmidi_in; + unsigned _midi_ins; + unsigned _midi_outs; + struct PortConnectData { std::string a; std::string b; diff --git a/libs/backends/alsa/alsa_midi.h b/libs/backends/alsa/alsa_midi.h index 7da991d66e..254835591f 100644 --- a/libs/backends/alsa/alsa_midi.h +++ b/libs/backends/alsa/alsa_midi.h @@ -42,6 +42,8 @@ public: virtual void* main_process_thread () = 0; + const std::string & name () const { return _name; } + protected: pthread_t _main_thread; pthread_mutex_t _notify_mutex; @@ -68,7 +70,8 @@ protected: RingBuffer* _rb; -protected: + std::string _name; + virtual void init (const char *device_name, const bool input) = 0; }; diff --git a/libs/backends/alsa/alsa_rawmidi.cc b/libs/backends/alsa/alsa_rawmidi.cc index e4678ba269..303649b9e7 100644 --- a/libs/backends/alsa/alsa_rawmidi.cc +++ b/libs/backends/alsa/alsa_rawmidi.cc @@ -38,10 +38,11 @@ using namespace ARDOUR; #define _DEBUGPRINT(STR) ; #endif -AlsaRawMidiIO::AlsaRawMidiIO (const char *device, const bool input) +AlsaRawMidiIO::AlsaRawMidiIO (const std::string &name, const char *device, const bool input) : AlsaMidiIO() , _device (0) { + _name = name; init (device, input); } @@ -107,8 +108,8 @@ initerr: /////////////////////////////////////////////////////////////////////////////// -AlsaRawMidiOut::AlsaRawMidiOut (const char *device) - : AlsaRawMidiIO (device, false) +AlsaRawMidiOut::AlsaRawMidiOut (const std::string &name, const char *device) + : AlsaRawMidiIO (name, device, false) , AlsaMidiOut () { } @@ -223,8 +224,8 @@ retry: /////////////////////////////////////////////////////////////////////////////// -AlsaRawMidiIn::AlsaRawMidiIn (const char *device) - : AlsaRawMidiIO (device, true) +AlsaRawMidiIn::AlsaRawMidiIn (const std::string &name, const char *device) + : AlsaRawMidiIO (name, device, true) , AlsaMidiIn () , _event(0,0) , _first_time(true) diff --git a/libs/backends/alsa/alsa_rawmidi.h b/libs/backends/alsa/alsa_rawmidi.h index 5d9a86c8db..654f084c4e 100644 --- a/libs/backends/alsa/alsa_rawmidi.h +++ b/libs/backends/alsa/alsa_rawmidi.h @@ -33,7 +33,7 @@ namespace ARDOUR { class AlsaRawMidiIO : virtual public AlsaMidiIO { public: - AlsaRawMidiIO (const char *device, const bool input); + AlsaRawMidiIO (const std::string &name, const char *device, const bool input); virtual ~AlsaRawMidiIO (); protected: @@ -46,14 +46,14 @@ private: class AlsaRawMidiOut : public AlsaRawMidiIO, public AlsaMidiOut { public: - AlsaRawMidiOut (const char *device); + AlsaRawMidiOut (const std::string &name, const char *device); void* main_process_thread (); }; class AlsaRawMidiIn : public AlsaRawMidiIO, public AlsaMidiIn { public: - AlsaRawMidiIn (const char *device); + AlsaRawMidiIn (const std::string &name, const char *device); void* main_process_thread (); diff --git a/libs/backends/alsa/alsa_sequencer.cc b/libs/backends/alsa/alsa_sequencer.cc index aa0aac09fa..cb77c3c48d 100644 --- a/libs/backends/alsa/alsa_sequencer.cc +++ b/libs/backends/alsa/alsa_sequencer.cc @@ -37,10 +37,11 @@ using namespace ARDOUR; #define _DEBUGPRINT(STR) ; #endif -AlsaSeqMidiIO::AlsaSeqMidiIO (const char *device, const bool input) +AlsaSeqMidiIO::AlsaSeqMidiIO (const std::string &name, const char *device, const bool input) : AlsaMidiIO() , _seq (0) { + _name = name; init (device, input); } @@ -117,8 +118,8 @@ initerr: /////////////////////////////////////////////////////////////////////////////// -AlsaSeqMidiOut::AlsaSeqMidiOut (const char *device) - : AlsaSeqMidiIO (device, false) +AlsaSeqMidiOut::AlsaSeqMidiOut (const std::string &name, const char *device) + : AlsaSeqMidiIO (name, device, false) , AlsaMidiOut () { } @@ -227,8 +228,8 @@ retry: /////////////////////////////////////////////////////////////////////////////// -AlsaSeqMidiIn::AlsaSeqMidiIn (const char *device) - : AlsaSeqMidiIO (device, true) +AlsaSeqMidiIn::AlsaSeqMidiIn (const std::string &name, const char *device) + : AlsaSeqMidiIO (name, device, true) , AlsaMidiIn () { } diff --git a/libs/backends/alsa/alsa_sequencer.h b/libs/backends/alsa/alsa_sequencer.h index bc00751acf..2c27778c97 100644 --- a/libs/backends/alsa/alsa_sequencer.h +++ b/libs/backends/alsa/alsa_sequencer.h @@ -33,7 +33,7 @@ namespace ARDOUR { class AlsaSeqMidiIO : virtual public AlsaMidiIO { public: - AlsaSeqMidiIO (const char *port_name, const bool input); + AlsaSeqMidiIO (const std::string &name, const char *port_name, const bool input); virtual ~AlsaSeqMidiIO (); protected: @@ -47,14 +47,14 @@ private: class AlsaSeqMidiOut : public AlsaSeqMidiIO, public AlsaMidiOut { public: - AlsaSeqMidiOut (const char *port_name); + AlsaSeqMidiOut (const std::string &name, const char *port_name); void* main_process_thread (); }; class AlsaSeqMidiIn : public AlsaSeqMidiIO, public AlsaMidiIn { public: - AlsaSeqMidiIn (const char *port_name); + AlsaSeqMidiIn (const std::string &name, const char *port_name); void* main_process_thread (); };