diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AlsaDriver.cpp | 60 | ||||
-rw-r--r-- | src/ClientInfo.hpp | 28 | ||||
-rw-r--r-- | src/JackDriver.cpp | 103 | ||||
-rw-r--r-- | src/JackDriver.hpp | 5 | ||||
-rw-r--r-- | src/PatchageEvent.hpp | 8 | ||||
-rw-r--r-- | src/PortInfo.hpp | 36 | ||||
-rw-r--r-- | src/PortNames.hpp | 15 |
7 files changed, 206 insertions, 49 deletions
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 0b32fe9..293ee63 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -17,10 +17,12 @@ #include "AlsaDriver.hpp" #include "ClientID.hpp" +#include "ClientInfo.hpp" #include "Patchage.hpp" #include "PatchageCanvas.hpp" #include "PatchageModule.hpp" #include "PatchagePort.hpp" +#include "PortInfo.hpp" #include "PortType.hpp" #include "SignalDirection.hpp" #include "handle_event.hpp" @@ -37,12 +39,50 @@ PATCHAGE_RESTORE_WARNINGS namespace { -inline PortID -addr_to_id(const snd_seq_addr_t& addr, bool is_input) +PortID +addr_to_id(const snd_seq_addr_t& addr, const bool is_input) { return PortID::alsa(addr.client, addr.port, is_input); } +SignalDirection +port_direction(const snd_seq_port_info_t* const pinfo) +{ + const int caps = snd_seq_port_info_get_capability(pinfo); + + if ((caps & SND_SEQ_PORT_CAP_READ) && (caps & SND_SEQ_PORT_CAP_WRITE)) { + return SignalDirection::duplex; + } + + if (caps & SND_SEQ_PORT_CAP_READ) { + return SignalDirection::output; + } + + if (caps & SND_SEQ_PORT_CAP_WRITE) { + return SignalDirection::input; + } + + return SignalDirection::duplex; +} + +ClientInfo +client_info(snd_seq_client_info_t* const cinfo) +{ + return {snd_seq_client_info_get_name(cinfo)}; +} + +PortInfo +port_info(const snd_seq_port_info_t* const pinfo) +{ + const int type = snd_seq_port_info_get_type(pinfo); + + return {snd_seq_port_info_get_name(pinfo), + PortType::alsa_midi, + port_direction(pinfo), + snd_seq_port_info_get_port(pinfo), + (type & SND_SEQ_PORT_TYPE_APPLICATION) == 0}; +} + } // namespace AlsaDriver::AlsaDriver(Patchage* app, ILog& log) @@ -568,7 +608,19 @@ AlsaDriver::_refresh_main() switch (ev->type) { case SND_SEQ_EVENT_CLIENT_START: + snd_seq_get_any_client_info(_seq, ev->data.addr.client, cinfo); + _events.emplace(ClientCreationEvent{ + ClientID::alsa(ev->data.addr.client), + client_info(cinfo), + }); + break; + case SND_SEQ_EVENT_CLIENT_EXIT: + _events.emplace(ClientDestructionEvent{ + ClientID::alsa(ev->data.addr.client), + }); + break; + case SND_SEQ_EVENT_CLIENT_CHANGE: break; @@ -580,7 +632,9 @@ AlsaDriver::_refresh_main() if (!ignore(ev->data.addr)) { _events.emplace(PortCreationEvent{ - addr_to_id(ev->data.addr, (caps & SND_SEQ_PORT_CAP_READ))}); + addr_to_id(ev->data.addr, (caps & SND_SEQ_PORT_CAP_READ)), + port_info(pinfo), + }); } break; diff --git a/src/ClientInfo.hpp b/src/ClientInfo.hpp new file mode 100644 index 0000000..9229d16 --- /dev/null +++ b/src/ClientInfo.hpp @@ -0,0 +1,28 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 David Robillard <d@drobilla.net> + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PATCHAGE_CLIENTINFO_HPP +#define PATCHAGE_CLIENTINFO_HPP + +#include <string> + +/// Extra information about a client (program) not expressed in its ID +struct ClientInfo +{ + std::string label; ///< Human-friendly label +}; + +#endif // PATCHAGE_CLIENTINFO_HPP diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp index 096b543..a491453 100644 --- a/src/JackDriver.cpp +++ b/src/JackDriver.cpp @@ -191,12 +191,12 @@ JackDriver::create_port_view(Patchage* patchage, const PortID& id) return port; } -#ifdef HAVE_JACK_METADATA static std::string -get_property(jack_uuid_t subject, const char* key) +get_property(const jack_uuid_t subject, const char* const key) { std::string result; +#ifdef HAVE_JACK_METADATA char* value = nullptr; char* datatype = nullptr; if (!jack_get_property(subject, key, &value, &datatype)) { @@ -204,66 +204,88 @@ get_property(jack_uuid_t subject, const char* key) } jack_free(datatype); jack_free(value); +#else + (void)subject; + (void)key; +#endif return result; } -#endif -PatchagePort* -JackDriver::create_port(PatchageModule& parent, - jack_port_t* port, - const PortID& id) +ClientInfo +JackDriver::get_client_info(const char* const name) { - if (!port) { - return nullptr; - } + return {name}; // TODO: Pretty name? +} - std::string label; - boost::optional<int> order; +PortInfo +JackDriver::get_port_info(const jack_port_t* const port) +{ + const auto uuid = jack_port_uuid(port); + const auto flags = jack_port_flags(port); + const std::string name = jack_port_name(port); + auto label = PortNames{name}.port(); + // Get pretty name to use as a label, if present #ifdef HAVE_JACK_METADATA - const jack_uuid_t uuid = jack_port_uuid(port); - if (_app->conf()->get_sort_ports()) { - const std::string order_str = get_property(uuid, JACKEY_ORDER); - label = get_property(uuid, JACK_METADATA_PRETTY_NAME); - if (!order_str.empty()) { - order = atoi(order_str.c_str()); - } + const auto pretty_name = get_property(uuid, JACK_METADATA_PRETTY_NAME); + if (!pretty_name.empty()) { + label = pretty_name; } #endif - const char* const type_str = jack_port_type(port); - PortType port_type = PortType::jack_audio; + // Determine detailed type, using metadata for fancy types if possible + const char* const type_str = jack_port_type(port); + PortType type = PortType::jack_audio; if (!strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) { - port_type = PortType::jack_audio; -#ifdef HAVE_JACK_METADATA if (get_property(uuid, JACKEY_SIGNAL_TYPE) == "CV") { - port_type = PortType::jack_cv; + type = PortType::jack_cv; } -#endif } else if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) { - port_type = PortType::jack_midi; -#ifdef HAVE_JACK_METADATA + type = PortType::jack_midi; if (get_property(uuid, JACKEY_EVENT_TYPES) == "OSC") { - port_type = PortType::jack_osc; + type = PortType::jack_osc; } -#endif } else { - _log.warning(fmt::format("[JACK] Port \"{}\" has unknown type \"{}\"", - jack_port_name(port), - type_str)); + _log.warning(fmt::format( + "[JACK] Port \"{}\" has unknown type \"{}\"", name, type_str)); + } + + // Get direction from port flags + const SignalDirection direction = + ((flags & JackPortIsInput) ? SignalDirection::input + : SignalDirection::output); + + // Get port order from metadata if possible + boost::optional<int> order; + const std::string order_str = get_property(uuid, JACKEY_ORDER); + if (!order_str.empty()) { + order = atoi(order_str.c_str()); + } + + return {label, type, direction, order, bool(flags & JackPortIsTerminal)}; +} + +PatchagePort* +JackDriver::create_port(PatchageModule& parent, + jack_port_t* port, + const PortID& id) +{ + if (!port) { return nullptr; } + const auto info = get_port_info(port); + auto* ret = new PatchagePort(parent, - port_type, + info.type, id, jack_port_short_name(port), - label, + info.label, (jack_port_flags(port) & JackPortIsInput), - _app->conf()->get_port_color(port_type), + _app->conf()->get_port_color(info.type), _app->show_human_names(), - order); + info.order); _app->canvas()->index_port(id, ret); @@ -485,11 +507,11 @@ JackDriver::jack_client_registration_cb(const char* name, int registered, void* jack_driver) { - auto* me = static_cast<JackDriver*>(jack_driver); + auto* const me = static_cast<JackDriver*>(jack_driver); assert(me->_client); if (registered) { - me->_events.emplace(ClientCreationEvent{ClientID::jack(name)}); + me->_events.emplace(ClientCreationEvent{ClientID::jack(name), {name}}); } else { me->_events.emplace(ClientDestructionEvent{ClientID::jack(name)}); } @@ -505,11 +527,12 @@ JackDriver::jack_port_registration_cb(jack_port_id_t port_id, jack_port_t* const port = jack_port_by_id(me->_client, port_id); const char* const name = jack_port_name(port); + const auto id = PortID::jack(name); if (registered) { - me->_events.emplace(PortCreationEvent{PortID::jack(name)}); + me->_events.emplace(PortCreationEvent{id, me->get_port_info(port)}); } else { - me->_events.emplace(PortDestructionEvent{PortID::jack(name)}); + me->_events.emplace(PortDestructionEvent{id}); } } diff --git a/src/JackDriver.hpp b/src/JackDriver.hpp index 402ebc7..6e41fbb 100644 --- a/src/JackDriver.hpp +++ b/src/JackDriver.hpp @@ -17,8 +17,10 @@ #ifndef PATCHAGE_JACKDRIVER_HPP #define PATCHAGE_JACKDRIVER_HPP +#include "ClientInfo.hpp" #include "Driver.hpp" #include "PatchageEvent.hpp" +#include "PortInfo.hpp" #include <glibmm/thread.h> #include <jack/jack.h> @@ -81,6 +83,9 @@ public: void process_events(Patchage* app) override; private: + ClientInfo get_client_info(const char* name); + PortInfo get_port_info(const jack_port_t* port); + PatchagePort* create_port(PatchageModule& parent, jack_port_t* port, const PortID& id); diff --git a/src/PatchageEvent.hpp b/src/PatchageEvent.hpp index 2a87a2e..d5add47 100644 --- a/src/PatchageEvent.hpp +++ b/src/PatchageEvent.hpp @@ -18,7 +18,9 @@ #define PATCHAGE_PATCHAGEEVENT_HPP #include "ClientID.hpp" +#include "ClientInfo.hpp" #include "PortID.hpp" +#include "PortInfo.hpp" #include <boost/variant/variant.hpp> @@ -26,7 +28,8 @@ struct ClientCreationEvent { - ClientID id; + ClientID id; + ClientInfo info; }; struct ClientDestructionEvent @@ -36,7 +39,8 @@ struct ClientDestructionEvent struct PortCreationEvent { - PortID id; + PortID id; + PortInfo info; }; struct PortDestructionEvent diff --git a/src/PortInfo.hpp b/src/PortInfo.hpp new file mode 100644 index 0000000..9b05c43 --- /dev/null +++ b/src/PortInfo.hpp @@ -0,0 +1,36 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 David Robillard <d@drobilla.net> + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PATCHAGE_PORTINFO_HPP +#define PATCHAGE_PORTINFO_HPP + +#include "PortType.hpp" +#include "SignalDirection.hpp" + +#include <boost/optional.hpp> +#include <string> + +/// Extra information about a port not expressed in its ID +struct PortInfo +{ + std::string label; ///< Human-friendly label + PortType type; ///< Detailed port type + SignalDirection direction; ///< Signal direction + boost::optional<int> order; ///< Order key on client + bool is_terminal; ///< True if this is a system port +}; + +#endif // PATCHAGE_PORTINFO_HPP diff --git a/src/PortNames.hpp b/src/PortNames.hpp index e976e34..f1f5391 100644 --- a/src/PortNames.hpp +++ b/src/PortNames.hpp @@ -24,13 +24,20 @@ class PortNames { public: + explicit PortNames(const std::string& jack_name) + { + const auto colon = jack_name.find(':'); + + if (colon != std::string::npos) { + _client_name = jack_name.substr(0, colon); + _port_name = jack_name.substr(colon + 1); + } + } + explicit PortNames(const PortID& id) + : PortNames(id.jack_name()) { assert(id.type() == PortID::Type::jack); - - const auto colon = id.jack_name().find(':'); - _client_name = id.jack_name().substr(0, colon); - _port_name = id.jack_name().substr(colon + 1); } const std::string& client() const { return _client_name; } |