summaryrefslogtreecommitdiffstats
path: root/src/JackDriver.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-11-28 21:41:26 +0100
committerDavid Robillard <d@drobilla.net>2020-11-28 22:49:10 +0100
commit5128bfab7ddb9504abf17375e910e5bc94af291e (patch)
tree79cc0953718e1f79ed47282b9f11f9f087edc3bc /src/JackDriver.cpp
parent0f25dd575f9c74cc34a54e64468f07e6c631750d (diff)
downloadpatchage-5128bfab7ddb9504abf17375e910e5bc94af291e.tar.gz
patchage-5128bfab7ddb9504abf17375e910e5bc94af291e.tar.bz2
patchage-5128bfab7ddb9504abf17375e910e5bc94af291e.zip
Refresh by emitting events
This decouples drivers from the rest of the application, in particular the horrible situation where they were working with the canvas directly, by having them always communicate changes by emitting events.
Diffstat (limited to 'src/JackDriver.cpp')
-rw-r--r--src/JackDriver.cpp244
1 files changed, 39 insertions, 205 deletions
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index a491453..cfcc541 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -21,8 +21,6 @@
#include "Patchage.hpp"
#include "PatchageCanvas.hpp"
#include "PatchageEvent.hpp"
-#include "PatchageModule.hpp"
-#include "PatchagePort.hpp"
#include "PortNames.hpp"
#include "PortType.hpp"
#include "SignalDirection.hpp"
@@ -45,10 +43,10 @@ PATCHAGE_RESTORE_WARNINGS
#include <cstring>
#include <set>
#include <string>
+#include <unordered_set>
-JackDriver::JackDriver(Patchage* app, ILog& log)
- : _app(app)
- , _log(log)
+JackDriver::JackDriver(ILog& log)
+ : _log(log)
, _client(nullptr)
, _last_pos{}
, _buffer_size(0)
@@ -119,78 +117,6 @@ JackDriver::detach()
_log.info("[JACK] Detached");
}
-static bool
-is_jack_port(const PatchagePort* port)
-{
- return (port->type() == PortType::jack_audio ||
- port->type() == PortType::jack_midi ||
- port->type() == PortType::jack_osc ||
- port->type() == PortType::jack_cv);
-}
-
-void
-JackDriver::destroy_all()
-{
- if (_app->canvas()) {
- _app->canvas()->remove_ports(is_jack_port);
- }
-}
-
-PatchagePort*
-JackDriver::create_port_view(Patchage* patchage, const PortID& id)
-{
- assert(id.type() == PortID::Type::jack);
-
- const auto client_id = id.client();
-
- jack_port_t* const jack_port =
- jack_port_by_name(_client, id.jack_name().c_str());
- if (!jack_port) {
- _log.error(fmt::format("[JACK] Failed to find port with name \"{}\"",
- id.jack_name()));
- return nullptr;
- }
-
- const int jack_flags = jack_port_flags(jack_port);
-
- std::string module_name;
- std::string port_name;
- port_names(id, module_name, port_name);
-
- SignalDirection type = SignalDirection::duplex;
- if (_app->conf()->get_module_split(module_name,
- (jack_flags & JackPortIsTerminal))) {
- if (jack_flags & JackPortIsInput) {
- type = SignalDirection::input;
- } else {
- type = SignalDirection::output;
- }
- }
-
- PatchageModule* parent = _app->canvas()->find_module(client_id, type);
- if (!parent) {
- parent = new PatchageModule(
- patchage, module_name, type, ClientID::jack(module_name));
- parent->load_location();
- patchage->canvas()->add_module(client_id, parent);
- }
-
- if (parent->get_port(id)) {
- _log.error(fmt::format("[JACK] Module \"{}\" already has port \"{}\"",
- module_name,
- port_name));
- return nullptr;
- }
-
- PatchagePort* port = create_port(*parent, jack_port, id);
- port->show();
- if (port->is_input()) {
- parent->set_is_source(false);
- }
-
- return port;
-}
-
static std::string
get_property(const jack_uuid_t subject, const char* const key)
{
@@ -266,32 +192,6 @@ JackDriver::get_port_info(const jack_port_t* const port)
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,
- info.type,
- id,
- jack_port_short_name(port),
- info.label,
- (jack_port_flags(port) & JackPortIsInput),
- _app->conf()->get_port_color(info.type),
- _app->show_human_names(),
- info.order);
-
- _app->canvas()->index_port(id, ret);
-
- return ret;
-}
-
void
JackDriver::shutdown()
{
@@ -299,133 +199,67 @@ JackDriver::shutdown()
}
void
-JackDriver::refresh()
+JackDriver::refresh(const EventSink& sink)
{
- jack_port_t* port = nullptr;
-
- // Jack can take _client away from us at any time throughout here :/
- // Shortest locks possible is the best solution I can figure out
-
std::lock_guard<std::mutex> lock{_shutdown_mutex};
- if (_client == nullptr) {
+ if (!_client) {
shutdown();
return;
}
// Get all existing ports
- const char** ports = jack_get_ports(_client, nullptr, nullptr, 0);
-
+ const char** const ports = jack_get_ports(_client, nullptr, nullptr, 0);
if (!ports) {
return;
}
- std::string client1_name;
- std::string port1_name;
- std::string client2_name;
- std::string port2_name;
- size_t colon = std::string::npos;
-
- // Add all ports
- for (int i = 0; ports[i]; ++i) {
- port = jack_port_by_name(_client, ports[i]);
-
- client1_name = ports[i];
- client1_name = client1_name.substr(0, client1_name.find(':'));
-
- SignalDirection type = SignalDirection::duplex;
- if (_app->conf()->get_module_split(
- client1_name, (jack_port_flags(port) & JackPortIsTerminal))) {
- if (jack_port_flags(port) & JackPortIsInput) {
- type = SignalDirection::input;
- } else {
- type = SignalDirection::output;
- }
- }
-
- const auto port1_id = PortID::jack(ports[i]);
- const auto client1_id = ClientID::jack(client1_name);
-
- PatchageModule* m = _app->canvas()->find_module(client1_id, type);
-
- if (!m) {
- m = new PatchageModule(_app, client1_name, type, client1_id);
- m->load_location();
- _app->canvas()->add_module(client1_id, m);
- }
-
- if (!m->get_port(port1_id)) {
- create_port(*m, port, PortID::jack(ports[i]));
- }
+ // Get all client names (to only send a creation event once for each)
+ std::unordered_set<std::string> client_names;
+ for (auto i = 0u; ports[i]; ++i) {
+ client_names.insert(PortID::jack(ports[i]).client().jack_name());
}
- // Add all connections
- for (int i = 0; ports[i]; ++i) {
- port = jack_port_by_name(_client, ports[i]);
- const char** connected_ports =
- jack_port_get_all_connections(_client, port);
-
- client1_name = ports[i];
- colon = client1_name.find(':');
- port1_name = client1_name.substr(colon + 1);
- client1_name = client1_name.substr(0, colon);
-
- const SignalDirection port1_type =
- (jack_port_flags(port) & JackPortIsInput) ? SignalDirection::input
- : SignalDirection::output;
-
- const auto port1_id = PortID::jack(ports[i]);
- const auto client1_id = ClientID::jack(client1_name);
-
- PatchageModule* client1_module =
- _app->canvas()->find_module(client1_id, port1_type);
-
- if (connected_ports) {
- for (int j = 0; connected_ports[j]; ++j) {
-
- client2_name = connected_ports[j];
- colon = client2_name.find(':');
- port2_name = client2_name.substr(colon + 1);
- client2_name = client2_name.substr(0, colon);
-
- const auto port2_id = PortID::jack(connected_ports[j]);
- const auto client2_id = ClientID::jack(client2_name);
-
- const SignalDirection port2_type =
- (port1_type == SignalDirection::input)
- ? SignalDirection::output
- : SignalDirection::input;
-
- PatchageModule* client2_module =
- _app->canvas()->find_module(client2_id, port2_type);
+ // Emit all clients
+ for (const auto& client_name : client_names) {
+ sink({ClientCreationEvent{ClientID::jack(client_name),
+ get_client_info(client_name.c_str())}});
+ }
- Ganv::Port* port1 = client1_module->get_port(port1_id);
- Ganv::Port* port2 = client2_module->get_port(port2_id);
+ // Emit all ports
+ for (auto i = 0u; ports[i]; ++i) {
+ const jack_port_t* const port = jack_port_by_name(_client, ports[i]);
- if (!port1 || !port2) {
- continue;
- }
+ sink({PortCreationEvent{PortID::jack(ports[i]), get_port_info(port)}});
+ }
- Ganv::Port* src = nullptr;
- Ganv::Port* dst = nullptr;
+ // Get all connections (again to only create them once)
+ std::set<std::pair<std::string, std::string>> connections;
+ for (auto i = 0u; ports[i]; ++i) {
+ const jack_port_t* const port = jack_port_by_name(_client, ports[i]);
+ const char** const peers = jack_port_get_all_connections(_client, port);
- if (port1->is_output() && port2->is_input()) {
- src = port1;
- dst = port2;
- } else {
- src = port2;
- dst = port1;
+ if (peers) {
+ if (jack_port_flags(port) & JackPortIsInput) {
+ for (auto j = 0u; peers[j]; ++j) {
+ connections.emplace(peers[j], ports[i]);
}
-
- if (src && dst && !_app->canvas()->get_edge(src, dst)) {
- _app->canvas()->make_connection(src, dst);
+ } else {
+ for (auto j = 0u; peers[j]; ++j) {
+ connections.emplace(ports[i], peers[j]);
}
}
- jack_free(connected_ports);
+ jack_free(peers);
}
}
+ // Emit all connections
+ for (const auto& connection : connections) {
+ sink({ConnectionEvent{PortID::jack(connection.first),
+ PortID::jack(connection.second)}});
+ }
+
jack_free(ports);
}