summaryrefslogtreecommitdiffstats
path: root/src/AlsaDriver.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/AlsaDriver.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/AlsaDriver.cpp')
-rw-r--r--src/AlsaDriver.cpp286
1 files changed, 51 insertions, 235 deletions
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp
index 293ee63..6e1cebb 100644
--- a/src/AlsaDriver.cpp
+++ b/src/AlsaDriver.cpp
@@ -20,8 +20,6 @@
#include "ClientInfo.hpp"
#include "Patchage.hpp"
#include "PatchageCanvas.hpp"
-#include "PatchageModule.hpp"
-#include "PatchagePort.hpp"
#include "PortInfo.hpp"
#include "PortType.hpp"
#include "SignalDirection.hpp"
@@ -33,6 +31,7 @@ PATCHAGE_DISABLE_FMT_WARNINGS
PATCHAGE_RESTORE_WARNINGS
#include <cassert>
+#include <limits>
#include <set>
#include <string>
#include <utility>
@@ -85,9 +84,8 @@ port_info(const snd_seq_port_info_t* const pinfo)
} // namespace
-AlsaDriver::AlsaDriver(Patchage* app, ILog& log)
- : _app(app)
- , _log(log)
+AlsaDriver::AlsaDriver(ILog& log)
+ : _log(log)
, _seq(nullptr)
, _refresh_thread{}
{}
@@ -136,32 +134,14 @@ AlsaDriver::detach()
}
}
-static bool
-is_alsa_port(const PatchagePort* port)
-{
- return port->type() == PortType::alsa_midi;
-}
-
void
-AlsaDriver::destroy_all()
+AlsaDriver::refresh(const EventSink& sink)
{
- _app->canvas()->remove_ports(is_alsa_port);
- _modules.clear();
- _port_addrs.clear();
-}
-
-void
-AlsaDriver::refresh()
-{
- if (!is_attached()) {
+ if (!is_attached() || !_seq) {
return;
}
- assert(_seq);
-
- _modules.clear();
_ignored.clear();
- _port_addrs.clear();
snd_seq_client_info_t* cinfo = nullptr;
snd_seq_client_info_alloca(&cinfo);
@@ -170,233 +150,74 @@ AlsaDriver::refresh()
snd_seq_port_info_t* pinfo = nullptr;
snd_seq_port_info_alloca(&pinfo);
- // Create port views
- {
- PatchageModule* parent = nullptr;
- PatchagePort* port = nullptr;
-
- while (snd_seq_query_next_client(_seq, cinfo) >= 0) {
- snd_seq_port_info_set_client(pinfo,
- snd_seq_client_info_get_client(cinfo));
- snd_seq_port_info_set_port(pinfo, -1);
- while (snd_seq_query_next_port(_seq, pinfo) >= 0) {
- const snd_seq_addr_t& addr = *snd_seq_port_info_get_addr(pinfo);
- if (ignore(addr)) {
- continue;
- }
+ // Emit all clients
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(_seq, cinfo) >= 0) {
+ const auto client_id = snd_seq_client_info_get_client(cinfo);
- create_port_view_internal(addr, parent, port);
- }
- }
+ assert(client_id < std::numeric_limits<uint8_t>::max());
+ sink({ClientCreationEvent{
+ ClientID::alsa(static_cast<uint8_t>(client_id)),
+ client_info(cinfo)}});
}
- // Create connections
+ // Emit all ports
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(_seq, cinfo) >= 0) {
- snd_seq_port_info_set_client(pinfo,
- snd_seq_client_info_get_client(cinfo));
+ const auto client_id = snd_seq_client_info_get_client(cinfo);
+
+ snd_seq_port_info_set_client(pinfo, client_id);
snd_seq_port_info_set_port(pinfo, -1);
while (snd_seq_query_next_port(_seq, pinfo) >= 0) {
- const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(pinfo);
- if (ignore(*addr)) {
- continue;
- }
-
- PatchagePort* const port1 = _app->canvas()->find_port(
- PortID::alsa(addr->client, addr->port, false));
- if (!port1) {
- continue;
- }
-
- snd_seq_query_subscribe_t* subsinfo = nullptr;
- snd_seq_query_subscribe_alloca(&subsinfo);
- snd_seq_query_subscribe_set_root(subsinfo, addr);
- snd_seq_query_subscribe_set_index(subsinfo, 0);
- while (!snd_seq_query_port_subscribers(_seq, subsinfo)) {
- const snd_seq_addr_t* addr2 =
- snd_seq_query_subscribe_get_addr(subsinfo);
- if (addr2) {
- const PortID id2 =
- PortID::alsa(addr2->client, addr2->port, true);
- PatchagePort* port2 = _app->canvas()->find_port(id2);
- if (port2 && !_app->canvas()->get_edge(port1, port2)) {
- _app->canvas()->make_connection(port1, port2);
- }
+ const auto addr = *snd_seq_port_info_get_addr(pinfo);
+ if (!ignore(addr)) {
+ const auto caps = snd_seq_port_info_get_capability(pinfo);
+ auto info = port_info(pinfo);
+
+ if (caps & SND_SEQ_PORT_CAP_READ) {
+ info.direction = SignalDirection::input;
+ sink({PortCreationEvent{addr_to_id(addr, true), info}});
}
- snd_seq_query_subscribe_set_index(
- subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1);
+ if (caps & SND_SEQ_PORT_CAP_WRITE) {
+ info.direction = SignalDirection::output;
+ sink({PortCreationEvent{addr_to_id(addr, false), info}});
+ }
}
}
}
-}
-
-PatchagePort*
-AlsaDriver::create_port_view(Patchage*, const PortID& id)
-{
- PatchageModule* parent = nullptr;
- PatchagePort* port = nullptr;
- create_port_view_internal({id.alsa_client(), id.alsa_port()}, parent, port);
-
- return port;
-}
-
-PatchageModule*
-AlsaDriver::find_module(uint8_t client_id, SignalDirection type)
-{
- const Modules::const_iterator i = _modules.find(client_id);
- if (i == _modules.end()) {
- return nullptr;
- }
-
- PatchageModule* io_module = nullptr;
- for (Modules::const_iterator j = i;
- j != _modules.end() && j->first == client_id;
- ++j) {
- if (j->second->type() == type) {
- return j->second;
- }
- if (j->second->type() == SignalDirection::duplex) {
- io_module = j->second;
- }
- }
-
- // Return InputOutput module for Input or Output, or null if not found
- return io_module;
-}
-
-PatchageModule*
-AlsaDriver::find_or_create_module(Patchage* patchage,
- uint8_t client_id,
- const std::string& client_name,
- SignalDirection type)
-{
- PatchageModule* m = find_module(client_id, type);
- if (!m) {
- m = new PatchageModule(
- patchage, client_name, type, ClientID::alsa(client_id));
- m->load_location();
- _app->canvas()->add_module(ClientID::alsa(client_id), m);
- _modules.insert(std::make_pair(client_id, m));
- }
- return m;
-}
-
-void
-AlsaDriver::create_port_view_internal(snd_seq_addr_t addr,
- PatchageModule*& parent,
- PatchagePort*& port)
-{
- if (ignore(addr)) {
- return;
- }
-
- snd_seq_client_info_t* cinfo = nullptr;
- snd_seq_client_info_alloca(&cinfo);
- snd_seq_client_info_set_client(cinfo, addr.client);
- snd_seq_get_any_client_info(_seq, addr.client, cinfo);
-
- snd_seq_port_info_t* pinfo = nullptr;
- snd_seq_port_info_alloca(&pinfo);
- snd_seq_port_info_set_client(pinfo, addr.client);
- snd_seq_port_info_set_port(pinfo, addr.port);
- snd_seq_get_any_port_info(_seq, addr.client, addr.port, pinfo);
-
- const std::string client_name = snd_seq_client_info_get_name(cinfo);
- const std::string port_name = snd_seq_port_info_get_name(pinfo);
- bool is_input = false;
- bool is_duplex = false;
- bool is_application = true;
-
- const int caps = snd_seq_port_info_get_capability(pinfo);
- const int type = snd_seq_port_info_get_type(pinfo);
-
- // Figure out direction
- if ((caps & SND_SEQ_PORT_CAP_READ) && (caps & SND_SEQ_PORT_CAP_WRITE)) {
- is_duplex = true;
- } else if (caps & SND_SEQ_PORT_CAP_READ) {
- is_input = false;
- } else if (caps & SND_SEQ_PORT_CAP_WRITE) {
- is_input = true;
- }
-
- is_application = (type & SND_SEQ_PORT_TYPE_APPLICATION);
-
- // Because there would be name conflicts, we must force a split if (stupid)
- // alsa duplex ports are present on the client
- bool split = false;
- if (is_duplex) {
- split = true;
- if (!_app->conf()->get_module_split(client_name, !is_application)) {
- _app->conf()->set_module_split(client_name, true);
- }
- } else {
- split = _app->conf()->get_module_split(client_name, !is_application);
- }
-
- const auto port_id = PortID::alsa(addr.client, addr.port, is_input);
+ // Emit all connections
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(_seq, cinfo) >= 0) {
+ const auto client_id = snd_seq_client_info_get_client(cinfo);
- if (!split) {
- parent = find_or_create_module(
- _app, addr.client, client_name, SignalDirection::duplex);
- if (!parent->get_port(port_id)) {
- port = create_port(*parent, port_name, is_input, addr);
- port->show();
- }
+ snd_seq_port_info_set_client(pinfo, client_id);
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(_seq, pinfo) >= 0) {
+ const auto tail_addr = *snd_seq_port_info_get_addr(pinfo);
+ const auto tail_id = addr_to_id(tail_addr, false);
+ if (ignore(tail_addr)) {
+ continue;
+ }
- } else { // split
- {
- const SignalDirection module_type =
- ((is_input) ? SignalDirection::input : SignalDirection::output);
+ snd_seq_query_subscribe_t* sinfo = nullptr;
+ snd_seq_query_subscribe_alloca(&sinfo);
+ snd_seq_query_subscribe_set_root(sinfo, &tail_addr);
+ snd_seq_query_subscribe_set_index(sinfo, 0);
+ while (!snd_seq_query_port_subscribers(_seq, sinfo)) {
+ const auto head_addr = *snd_seq_query_subscribe_get_addr(sinfo);
+ const auto head_id = addr_to_id(head_addr, true);
- parent = find_or_create_module(
- _app, addr.client, client_name, module_type);
- if (!parent->get_port(port_id)) {
- port = create_port(*parent, port_name, is_input, addr);
- port->show();
- }
- }
+ sink({ConnectionEvent{tail_id, head_id}});
- if (is_duplex) {
- const SignalDirection flipped_module_type =
- ((!is_input) ? SignalDirection::input
- : SignalDirection::output);
- parent = find_or_create_module(
- _app, addr.client, client_name, flipped_module_type);
- if (!parent->get_port(port_id)) {
- port = create_port(*parent, port_name, !is_input, addr);
- port->show();
+ snd_seq_query_subscribe_set_index(
+ sinfo, snd_seq_query_subscribe_get_index(sinfo) + 1);
}
}
}
}
-PatchagePort*
-AlsaDriver::create_port(PatchageModule& parent,
- const std::string& name,
- bool is_input,
- snd_seq_addr_t addr)
-{
- const PortID id = PortID::alsa(addr.client, addr.port, is_input);
-
- auto* ret =
- new PatchagePort(parent,
- PortType::alsa_midi,
- id,
- name,
- "",
- is_input,
- _app->conf()->get_port_color(PortType::alsa_midi),
- _app->show_human_names());
-
- dynamic_cast<PatchageCanvas*>(parent.canvas())->index_port(id, ret);
-
- _app->canvas()->index_port(id, ret);
- _port_addrs.insert(std::make_pair(ret, id));
- return ret;
-}
-
bool
AlsaDriver::ignore(const snd_seq_addr_t& addr, bool add)
{
@@ -646,11 +467,6 @@ AlsaDriver::_refresh_main()
PortDestructionEvent{addr_to_id(ev->data.addr, true)});
_events.emplace(
PortDestructionEvent{addr_to_id(ev->data.addr, false)});
-
- _port_addrs.erase(_app->canvas()->find_port(
- addr_to_id(ev->data.addr, false)));
- _port_addrs.erase(
- _app->canvas()->find_port(addr_to_id(ev->data.addr, true)));
}
break;