diff --git a/libs/ctrl-interface/midi_surface/midi_surface.cc b/libs/ctrl-interface/midi_surface/midi_surface.cc index 856850da84..c50235ccfa 100644 --- a/libs/ctrl-interface/midi_surface/midi_surface.cc +++ b/libs/ctrl-interface/midi_surface/midi_surface.cc @@ -16,6 +16,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + #include "pbd/debug.h" #include "pbd/i18n.h" @@ -167,20 +169,79 @@ MIDISurface::port_registration_handler () return; } - std::vector in; - std::vector out; + std::vector midi_inputs; + std::vector midi_outputs; - AudioEngine::instance()->get_ports (string_compose (".*%1", input_port_name()), DataType::MIDI, PortFlags (IsPhysical|IsOutput), in); - AudioEngine::instance()->get_ports (string_compose (".*%1", output_port_name()), DataType::MIDI, PortFlags (IsPhysical|IsInput), out); + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsPhysical|IsOutput), midi_inputs); + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsPhysical|IsInput), midi_outputs); - if (!in.empty() && !out.empty()) { - if (!_async_in->connected()) { - AudioEngine::instance()->connect (_async_in->name(), in.front()); + if (midi_inputs.empty() || midi_outputs.empty()) { + return; + } + + /* Try to find the input & output ports, whose pretty name varies on + * Linux depending on the version of ALSA, but is fairly consistent + * across newer ALSA and other platforms. + */ + + /* See if the input port is available, and maybe connect that */ + + string ip = input_port_name (); + + if (ip[0] == ':') { + std::regex rx (ip.substr (1), std::regex::extended); + + auto is_the_input = [&rx](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return std::regex_search (pn, rx); + }; + + auto pi = std::find_if (midi_inputs.begin(), midi_inputs.end(), is_the_input); + if (pi != midi_inputs.end()) { + AudioEngine::instance()->connect (_async_in->name(), *pi); } - if (!_async_out->connected()) { - AudioEngine::instance()->connect (_async_out->name(), out.front()); + } else { + /* regular partial string search */ + auto is_the_input = [&ip](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return pn.find (ip) != string::npos; + }; + + auto pi = std::find_if (midi_inputs.begin(), midi_inputs.end(), is_the_input); + if (pi != midi_inputs.end()) { + AudioEngine::instance()->connect (_async_in->name(), *pi); } } + + /* Now see if the output port is available, and maybe connect that */ + + string op = output_port_name (); + + if (op[0] == ':') { + std::regex rx (op.substr (1), std::regex::extended); + + auto is_the_output = [&rx](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return std::regex_search (pn, rx); + }; + + auto po = std::find_if (midi_outputs.begin(), midi_outputs.end(), is_the_output); + if (po != midi_outputs.end()) { + AudioEngine::instance()->connect (_async_in->name(), *po); + } + } else { + /* regular partial string search */ + auto is_the_output = [&op](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return pn.find (op) != string::npos; + }; + + auto po = std::find_if (midi_outputs.begin(), midi_outputs.end(), is_the_output); + if (po != midi_outputs.end()) { + AudioEngine::instance()->connect (_async_in->name(), *po); + } + + } } bool @@ -442,4 +503,3 @@ MIDISurface::bundles () return b; } - diff --git a/libs/ctrl-interface/midi_surface/midi_surface/midi_surface.h b/libs/ctrl-interface/midi_surface/midi_surface/midi_surface.h index 18c71205c4..301fc29670 100644 --- a/libs/ctrl-interface/midi_surface/midi_surface/midi_surface.h +++ b/libs/ctrl-interface/midi_surface/midi_surface/midi_surface.h @@ -58,6 +58,17 @@ class MIDISurface : public ARDOUR::ControlProtocol ARDOUR::Session & get_session() { return *session; } + /* These two names are used in a port registration handler to try to + automatically connect the device when it is discovered. + + If the value returned by these methods begins with a colon, they + will be assumed to be regular expressions, and passed (without the + leading colon) into the constructor of a std::regex using + std::regex::extended syntax. + + Otherwise, they are assumed to be unique string identifiers, and are + merely searched for in port names with std::string::find(). + */ virtual std::string input_port_name () const = 0; virtual std::string output_port_name () const = 0; diff --git a/libs/surfaces/launchpad_pro/lppro.cc b/libs/surfaces/launchpad_pro/lppro.cc index 746c17c0a6..3f4190facd 100644 --- a/libs/surfaces/launchpad_pro/lppro.cc +++ b/libs/surfaces/launchpad_pro/lppro.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -110,15 +111,26 @@ LaunchPadPro::probe (std::string& i, std::string& o) { vector midi_inputs; vector midi_outputs; - AudioEngine::instance()->get_ports (string_compose (".*%1", input_port_regex()), DataType::MIDI, PortFlags (IsOutput|IsTerminal), midi_inputs); - AudioEngine::instance()->get_ports (string_compose (".*%1", output_port_regex()), DataType::MIDI, PortFlags (IsInput|IsTerminal), midi_outputs); + + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsOutput|IsTerminal), midi_inputs); + AudioEngine::instance()->get_ports("", DataType::MIDI, PortFlags(IsInput | IsTerminal), midi_outputs); if (midi_inputs.empty() || midi_outputs.empty()) { return false; } - i = midi_inputs.front(); - o = midi_inputs.front(); + std::regex rx (X_("Launchpad Pro MK3.*MIDI")); + + auto has_lppro = [&rx](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return std::regex_search (pn, rx); + }; + + auto pi = std::find_if (midi_inputs.begin(), midi_inputs.end(), has_lppro); + auto po = std::find_if (midi_outputs.begin (), midi_outputs.end (), has_lppro); + + i = *pi; + o = *po; return true; } @@ -322,53 +334,13 @@ LaunchPadPro::set_state (const XMLNode & node, int version) std::string LaunchPadPro::input_port_name () const { - return input_port_regex(); -} - -std::string -LaunchPadPro::input_port_regex () -{ -#ifdef __APPLE__ - return X_("Launchpad Pro MK3.*MIDI In"); -#else - return X_("Launchpad Pro MK3.*MIDI 1"); -#endif -} - -std::string -LaunchPadPro::input_daw_port_regex () -{ -#ifdef __APPLE__ - return X_("Launchpad Pro MK3.*DAW"); -#else - return X_("Launchpad Pro MK3.*MIDI 3"); -#endif + return X_(":Launchpad Pro MK3.*MIDI (In|1)"); } std::string LaunchPadPro::output_port_name () const { - return output_port_regex(); -} - -std::string -LaunchPadPro::output_port_regex() -{ -#ifdef __APPLE__ - return X_("Launchpad Pro MK3.*MIDI Out"); -#else - return X_("Launchpad Pro MK3.*MIDI 1"); -#endif -} - -std::string -LaunchPadPro::output_daw_port_regex () -{ -#ifdef __APPLE__ - return X_("Launchpad Pro MK3.*DAW"); -#else - return X_("Launchpad Pro MK3.*MIDI 3"); -#endif + return X_(":Launchpad Pro MK3.*MIDI (Out|1)"); } void @@ -856,21 +828,40 @@ LaunchPadPro::connect_daw_ports () return; } - std::vector in; - std::vector out; - AudioEngine::instance()->get_ports (string_compose (".*%1", input_daw_port_regex()), DataType::MIDI, PortFlags (IsPhysical|IsOutput), in); - AudioEngine::instance()->get_ports (string_compose (".*%1", output_daw_port_regex()), DataType::MIDI, PortFlags (IsPhysical|IsInput), out); + std::vector midi_inputs; + std::vector midi_outputs; - if (!in.empty() && !out.empty()) { + /* get all MIDI Ports */ - if (!_daw_in->connected()) { - AudioEngine::instance()->connect (_daw_in->name(), in.front()); - } + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsOutput|IsTerminal), midi_inputs); + AudioEngine::instance()->get_ports("", DataType::MIDI, PortFlags(IsInput | IsTerminal), midi_outputs); - if (!_daw_out->connected()) { - AudioEngine::instance()->connect (_daw_out->name(), out.front()); - } + if (midi_inputs.empty() || midi_outputs.empty()) { + return; } + + /* Try to find the DAW port, whose pretty name varies on Linux + * depending on the version of ALSA, but is fairly consistent across + * newer ALSA and other platforms. + */ + + std::regex rx (X_("Launchpad Pro MK3.*(DAW|MIDI 3)"), std::regex::extended); + + auto is_dawport = [&rx](string const &s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name(s); + return std::regex_search (pn, rx); + }; + + auto pi = std::find_if (midi_inputs.begin(), midi_inputs.end(), is_dawport); + auto po = std::find_if (midi_outputs.begin (), midi_outputs.end (), is_dawport); + + if (!_daw_in->connected()) { + AudioEngine::instance()->connect (_daw_in->name(), *pi); + } + + if (!_daw_out->connected()) { + AudioEngine::instance()->connect (_daw_out->name(), *po); + } } int @@ -1074,7 +1065,7 @@ LaunchPadPro::stripable_selection_changed () } } - + } bool diff --git a/libs/surfaces/launchpad_pro/lppro.h b/libs/surfaces/launchpad_pro/lppro.h index b3135f9918..16432fe81b 100644 --- a/libs/surfaces/launchpad_pro/lppro.h +++ b/libs/surfaces/launchpad_pro/lppro.h @@ -292,10 +292,6 @@ class LaunchPadPro : public MIDISurface void port_registration_handler (); int ports_acquire (); void ports_release (); - static std::string input_port_regex (); - static std::string output_port_regex (); - static std::string input_daw_port_regex (); - static std::string output_daw_port_regex (); void connect_daw_ports (); void daw_write (const MidiByteArray&);