summaryrefslogtreecommitdiffstats
path: root/src/AlsaDriver.cpp
diff options
context:
space:
mode:
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;