summaryrefslogtreecommitdiffstats
path: root/src/AlsaDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/AlsaDriver.cpp')
-rw-r--r--src/AlsaDriver.cpp284
1 files changed, 152 insertions, 132 deletions
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp
index a22ecc8..b2ceed7 100644
--- a/src/AlsaDriver.cpp
+++ b/src/AlsaDriver.cpp
@@ -18,6 +18,7 @@
#include <cassert>
#include <set>
#include <string>
+#include <utility>
#include "raul/SharedPtr.hpp"
#include "raul/log.hpp"
@@ -94,6 +95,8 @@ void
AlsaDriver::destroy_all()
{
_app->canvas()->remove_ports(is_alsa_port);
+ _modules.clear();
+ _port_addrs.clear();
}
/** Refresh all Alsa Midi ports and connections.
@@ -106,32 +109,122 @@ AlsaDriver::refresh()
assert(_seq);
- refresh_ports();
- refresh_connections();
+ _modules.clear();
+ _ignored.clear();
+ _port_addrs.clear();
+
+ snd_seq_client_info_t* cinfo;
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+
+ snd_seq_port_info_t* pinfo;
+ snd_seq_port_info_alloca(&pinfo);
+
+ PatchageModule* parent = NULL;
+ PatchagePort* port = NULL;
+
+ // Create port views
+ 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;
+ }
+
+ create_port_view_internal(_app, addr, parent, port);
+ if (parent) {
+ _app->enqueue_resize(parent);
+ }
+ }
+ }
+
+ // Create connections
+ 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));
+ 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* port = _app->canvas()->find_port(PortID(*addr, false));
+ if (!port) {
+ continue;
+ }
+
+ snd_seq_query_subscribe_t* subsinfo;
+ 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)
+ continue;
+
+ PatchagePort* port2 = _app->canvas()->find_port(PortID(*addr2, true));
+ if (port2 && !port->is_connected_to(port2)) {
+ _app->canvas()->add_connection(port,
+ port2,
+ port->color() + 0x22222200);
+
+ snd_seq_query_subscribe_set_index(
+ subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1);
+ }
+ }
+ }
+ }
}
PatchagePort*
AlsaDriver::create_port_view(Patchage* patchage,
const PortID& id)
{
- PatchageModule* parent;
- PatchagePort* port;
+ PatchageModule* parent = NULL;
+ PatchagePort* port = NULL;
create_port_view_internal(patchage, id.id.alsa_addr, parent, port);
return port;
}
PatchageModule*
+AlsaDriver::find_module(uint8_t client_id, ModuleType type)
+{
+ const Modules::const_iterator i = _modules.find(client_id);
+ if (i == _modules.end())
+ return NULL;
+
+ PatchageModule* io_module = NULL;
+ for (Modules::const_iterator j = i;
+ j != _modules.end() && j->first == client_id;
+ ++j) {
+ if (j->second->type() == type) {
+ return j->second;
+ } else if (j->second->type() == InputOutput) {
+ 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,
ModuleType type)
{
- PatchageModule* m = _app->canvas()->find_module(client_name, type);
+ PatchageModule* m = find_module(client_id, type);
if (!m) {
m = new PatchageModule(patchage, client_name, type);
m->load_location();
_app->canvas()->add_module(client_name, m);
_app->enqueue_resize(m);
+ _modules.insert(std::make_pair(client_id, m));
}
return m;
}
@@ -196,29 +289,26 @@ AlsaDriver::create_port_view_internal(
<< " split = " << split << endl;*/
if (!split) {
- m = find_or_create_module(_app, client_name, InputOutput);
+ m = find_or_create_module(_app, addr.client, client_name, InputOutput);
if (!m->get_port(port_name)) {
port = create_port(*m, port_name, is_input, addr);
port->show();
- m->add_port(port);
}
} else { // split
ModuleType type = ((is_input) ? Input : Output);
- m = find_or_create_module(_app, client_name, type);
+ m = find_or_create_module(_app, addr.client, client_name, type);
if (!m->get_port(port_name)) {
port = create_port(*m, port_name, is_input, addr);
port->show();
- m->add_port(port);
}
if (is_duplex) {
type = ((!is_input) ? Input : Output);
- m = find_or_create_module(_app, client_name, type);
+ m = find_or_create_module(_app, addr.client, client_name, type);
if (!m->get_port(port_name)) {
port = create_port(*m, port_name, !is_input, addr);
port->show();
- m->add_port(port);
}
}
}
@@ -235,7 +325,8 @@ AlsaDriver::create_port(PatchageModule& parent,
dynamic_cast<PatchageCanvas*>(parent.canvas())->index_port(
PortID(addr, is_input), ret);
- ret->alsa_addr(addr);
+ _app->canvas()->index_port(PortID(addr, is_input), ret);
+ _port_addrs.insert(std::make_pair(ret, PortID(addr, is_input)));
return ret;
}
@@ -280,101 +371,6 @@ AlsaDriver::ignore(const snd_seq_addr_t& addr, bool add)
return false;
}
-/** Refresh all Alsa Midi ports.
- */
-void
-AlsaDriver::refresh_ports()
-{
- assert(is_attached());
- assert(_seq);
-
- snd_seq_client_info_t* cinfo;
- snd_seq_client_info_alloca(&cinfo);
- snd_seq_client_info_set_client(cinfo, -1);
-
- snd_seq_port_info_t* pinfo;
- snd_seq_port_info_alloca(&pinfo);
-
- PatchageModule* parent;
- PatchagePort* port;
-
- std::set<PatchageModule*> to_resize;
-
- 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)) {
- create_port_view_internal(_app, addr, parent, port);
- if (parent)
- _app->enqueue_resize(parent);
- }
- }
- }
-}
-
-/** Refresh all Alsa Midi connections.
- */
-void
-AlsaDriver::refresh_connections()
-{
- assert(is_attached());
- assert(_seq);
-
- PatchageModule* m = NULL;
- PatchagePort* p = NULL;
-
- for (FlowCanvas::Canvas::Items::iterator i = _app->canvas()->items().begin();
- i != _app->canvas()->items().end(); ++i) {
- m = dynamic_cast<PatchageModule*>(*i);
- if (m) {
- for (FlowCanvas::Module::Ports::const_iterator j = m->ports().begin(); j != m->ports().end(); ++j) {
- p = dynamic_cast<PatchagePort*>(*j);
- if (p->type() == ALSA_MIDI)
- add_connections(p);
- }
- }
- }
-}
-
-/** Add all connections for the given port.
- */
-void
-AlsaDriver::add_connections(PatchagePort* port)
-{
- assert(is_attached());
- assert(_seq);
-
- const snd_seq_addr_t* addr = port->alsa_addr();
- PatchagePort* connected_port;
-
- // Fix a problem with duplex->duplex connections (would show up twice)
- // No sense doing them all twice anyway..
- if (port->is_input())
- return;
-
- snd_seq_query_subscribe_t* subsinfo;
- 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* connected_addr = snd_seq_query_subscribe_get_addr(subsinfo);
- if (!connected_addr)
- continue;
-
- PortID id(*connected_addr, true);
- connected_port = _app->canvas()->find_port(id);
-
- if (connected_port && !port->is_connected_to(connected_port))
- _app->canvas()->add_connection(port, connected_port, port->color() + 0x22222200);
-
- snd_seq_query_subscribe_set_index(subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1);
- }
-
-}
-
/** Connects two Alsa Midi ports.
*
* \return Whether connection succeeded.
@@ -383,31 +379,43 @@ bool
AlsaDriver::connect(PatchagePort* src_port,
PatchagePort* dst_port)
{
- const snd_seq_addr_t* src = src_port->alsa_addr();
- const snd_seq_addr_t* dst = dst_port->alsa_addr();
+ PortAddrs::const_iterator s = _port_addrs.find(src_port);
+ PortAddrs::const_iterator d = _port_addrs.find(dst_port);
+
+ if (s == _port_addrs.end() || d == _port_addrs.end()) {
+ Raul::error << "[ALSA] Attempt to connect port with no address" << endl;
+ return false;
+ }
+
+ const PortID src = s->second;
+ const PortID dst = d->second;
+
+ if (src.id.alsa_addr.client == dst.id.alsa_addr.client
+ && src.id.alsa_addr.port == dst.id.alsa_addr.port) {
+ Raul::warn << "[ALSA] Refusing to connect port to itself" << endl;
+ return false;
+ }
bool result = true;
- if (src && dst) {
- snd_seq_port_subscribe_t* subs;
- snd_seq_port_subscribe_malloc(&subs);
- snd_seq_port_subscribe_set_sender(subs, src);
- snd_seq_port_subscribe_set_dest(subs, dst);
- snd_seq_port_subscribe_set_exclusive(subs, 0);
- snd_seq_port_subscribe_set_time_update(subs, 0);
- snd_seq_port_subscribe_set_time_real(subs, 0);
-
- // Already connected (shouldn't happen)
- if (!snd_seq_get_port_subscription(_seq, subs)) {
- Raul::error << "[ALSA] Attempt to subscribe ports that are already subscribed." << endl;
- result = false;
- }
+ snd_seq_port_subscribe_t* subs;
+ snd_seq_port_subscribe_malloc(&subs);
+ snd_seq_port_subscribe_set_sender(subs, &src.id.alsa_addr);
+ snd_seq_port_subscribe_set_dest(subs, &dst.id.alsa_addr);
+ snd_seq_port_subscribe_set_exclusive(subs, 0);
+ snd_seq_port_subscribe_set_time_update(subs, 0);
+ snd_seq_port_subscribe_set_time_real(subs, 0);
- int ret = snd_seq_subscribe_port(_seq, subs);
- if (ret < 0) {
- Raul::error << "[ALSA] Subscription failed: " << snd_strerror(ret) << endl;
- result = false;
- }
+ // Already connected (shouldn't happen)
+ if (!snd_seq_get_port_subscription(_seq, subs)) {
+ Raul::error << "[ALSA] Attempt to double subscribe ports" << endl;
+ result = false;
+ }
+
+ int ret = snd_seq_subscribe_port(_seq, subs);
+ if (ret < 0) {
+ Raul::error << "[ALSA] Subscription failed: " << snd_strerror(ret) << endl;
+ result = false;
}
if (result)
@@ -428,13 +436,21 @@ bool
AlsaDriver::disconnect(PatchagePort* src_port,
PatchagePort* dst_port)
{
- const snd_seq_addr_t* src = src_port->alsa_addr();
- const snd_seq_addr_t* dst = dst_port->alsa_addr();
+ PortAddrs::const_iterator s = _port_addrs.find(src_port);
+ PortAddrs::const_iterator d = _port_addrs.find(dst_port);
+
+ if (s == _port_addrs.end() || d == _port_addrs.end()) {
+ Raul::error << "[ALSA] Attempt to connect port with no address" << endl;
+ return false;
+ }
+
+ const PortID src = s->second;
+ const PortID dst = d->second;
snd_seq_port_subscribe_t* subs;
snd_seq_port_subscribe_malloc(&subs);
- snd_seq_port_subscribe_set_sender(subs, src);
- snd_seq_port_subscribe_set_dest(subs, dst);
+ snd_seq_port_subscribe_set_sender(subs, &src.id.alsa_addr);
+ snd_seq_port_subscribe_set_dest(subs, &dst.id.alsa_addr);
snd_seq_port_subscribe_set_exclusive(subs, 0);
snd_seq_port_subscribe_set_time_update(subs, 0);
snd_seq_port_subscribe_set_time_real(subs, 0);
@@ -547,6 +563,10 @@ AlsaDriver::_refresh_main()
PortID(ev->data.addr, true)));
_events.push(PatchageEvent(PatchageEvent::PORT_DESTRUCTION,
PortID(ev->data.addr, false)));
+ _port_addrs.erase(_app->canvas()->find_port(
+ PortID(ev->data.addr, false)));
+ _port_addrs.erase(_app->canvas()->find_port(
+ PortID(ev->data.addr, true)));
}
break;
case SND_SEQ_EVENT_CLIENT_CHANGE: