summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-11-28 19:31:25 +0100
committerDavid Robillard <d@drobilla.net>2020-11-28 22:49:10 +0100
commit1c5decf5f85b7808a70885c820596fac013cf644 (patch)
tree34f873fc6099df1e08af0dd7898f67404622b1f0 /src
parent37a33e5549354b6142ce4aeacd6a7c627e772f48 (diff)
downloadpatchage-1c5decf5f85b7808a70885c820596fac013cf644.tar.gz
patchage-1c5decf5f85b7808a70885c820596fac013cf644.tar.bz2
patchage-1c5decf5f85b7808a70885c820596fac013cf644.zip
Factor out getting client and port metadata and send it with events
Diffstat (limited to 'src')
-rw-r--r--src/AlsaDriver.cpp60
-rw-r--r--src/ClientInfo.hpp28
-rw-r--r--src/JackDriver.cpp103
-rw-r--r--src/JackDriver.hpp5
-rw-r--r--src/PatchageEvent.hpp8
-rw-r--r--src/PortInfo.hpp36
-rw-r--r--src/PortNames.hpp15
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; }