summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-05-09 23:59:01 +0000
committerDavid Robillard <d@drobilla.net>2009-05-09 23:59:01 +0000
commit5465c4af1c7b18cba31fa3d15ab1741f2613e9d4 (patch)
treea7331689f196cef1e979afa313ba60122fa64a97
parent43e673a183844709ecd41e08d97f96d9228a544c (diff)
downloadpatchage-5465c4af1c7b18cba31fa3d15ab1741f2613e9d4.tar.gz
patchage-5465c4af1c7b18cba31fa3d15ab1741f2613e9d4.tar.bz2
patchage-5465c4af1c7b18cba31fa3d15ab1741f2613e9d4.zip
Dramatically reduce resize overhead everywhere.
Make alsa driver create individual ports and do minimal work vs naive full refresh when anything changes. Fixes ticket #355. git-svn-id: http://svn.drobilla.net/lad/trunk/patchage@1967 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/AlsaDriver.cpp310
-rw-r--r--src/AlsaDriver.hpp13
-rw-r--r--src/JackDbusDriver.cpp6
-rw-r--r--src/JackDriver.cpp26
-rw-r--r--src/Patchage.cpp26
-rw-r--r--src/Patchage.hpp21
-rw-r--r--src/PatchageEvent.cpp9
-rw-r--r--src/PatchageModule.hpp1
8 files changed, 218 insertions, 194 deletions
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp
index 25a9105..32c5f24 100644
--- a/src/AlsaDriver.cpp
+++ b/src/AlsaDriver.cpp
@@ -101,12 +101,130 @@ AlsaDriver::refresh()
refresh_connections();
}
-
+
boost::shared_ptr<PatchagePort>
AlsaDriver::create_port_view(Patchage* patchage,
const PortID& id)
{
- return boost::shared_ptr<PatchagePort>();
+ boost::shared_ptr<PatchageModule> parent;
+ boost::shared_ptr<PatchagePort> port;
+ create_port_view_internal(patchage, id.id.alsa_addr, parent, port);
+ return port;
+}
+
+
+boost::shared_ptr<PatchageModule>
+AlsaDriver::find_or_create_module(
+ Patchage* patchage,
+ const std::string& client_name,
+ ModuleType type)
+{
+ boost::shared_ptr<PatchageModule> m = _app->canvas()->find_module(client_name, type);
+ if (!m) {
+ m = boost::shared_ptr<PatchageModule>(new PatchageModule(patchage, client_name, type));
+ m->load_location();
+ _app->canvas()->add_item(m);
+ _app->enqueue_resize(m);
+ }
+ return m;
+}
+
+
+void
+AlsaDriver::create_port_view_internal(
+ Patchage* patchage,
+ snd_seq_addr_t addr,
+ boost::shared_ptr<PatchageModule>& m,
+ boost::shared_ptr<PatchagePort>& port)
+{
+ snd_seq_client_info_t* cinfo;
+ 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;
+ 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 string client_name = snd_seq_client_info_get_name(cinfo);
+ const string port_name = snd_seq_port_info_get_name(pinfo);
+ bool is_input = false;
+ bool is_duplex = false;
+ bool is_application = true;
+ bool need_refresh = false;
+
+ int caps = snd_seq_port_info_get_capability(pinfo);
+ int type = snd_seq_port_info_get_type(pinfo);
+
+ // Skip ports we shouldn't show
+ if (caps & SND_SEQ_PORT_CAP_NO_EXPORT)
+ return;
+ else if ( !( (caps & SND_SEQ_PORT_CAP_READ)
+ || (caps & SND_SEQ_PORT_CAP_WRITE)
+ || (caps & SND_SEQ_PORT_CAP_DUPLEX)))
+ return;
+ else if ((snd_seq_client_info_get_type(cinfo) != SND_SEQ_USER_CLIENT)
+ && ((type == SND_SEQ_PORT_SYSTEM_TIMER
+ || type == SND_SEQ_PORT_SYSTEM_ANNOUNCE)))
+ return;
+
+ // 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->state_manager()->get_module_split(client_name, !is_application)) {
+ need_refresh = true;
+ _app->state_manager()->set_module_split(client_name, true);
+ }
+ } else {
+ split = _app->state_manager()->get_module_split(client_name, !is_application);
+ }
+
+ /*cout << "ALSA PORT: " << client_name << " : " << port_name
+ << " is_application = " << is_application
+ << " is_duplex = " << is_duplex
+ << " split = " << split << endl;*/
+
+ if (!split) {
+ m = find_or_create_module(_app, 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);
+ 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);
+ if (!m->get_port(port_name)) {
+ port = create_port(m, port_name, !is_input, addr);
+ port->show();
+ m->add_port(port);
+ }
+ }
+ }
}
@@ -129,7 +247,7 @@ 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);
@@ -137,161 +255,18 @@ AlsaDriver::refresh_ports()
snd_seq_port_info_t* pinfo;
snd_seq_port_info_alloca(&pinfo);
- string client_name;
- string port_name;
- bool is_input = false;
- bool is_duplex = false;
- bool is_application = true;
- bool need_refresh = false;
+ boost::shared_ptr<PatchageModule> parent;
+ boost::shared_ptr<PatchagePort> port;
set< boost::shared_ptr<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);
-
- client_name = snd_seq_client_info_get_name(cinfo);
-
while (snd_seq_query_next_port(_seq, pinfo) >= 0) {
- int caps = snd_seq_port_info_get_capability(pinfo);
- int type = snd_seq_port_info_get_type(pinfo);
-
- // Skip ports we shouldn't show
- if (caps & SND_SEQ_PORT_CAP_NO_EXPORT)
- continue;
- else if ( !( (caps & SND_SEQ_PORT_CAP_READ)
- || (caps & SND_SEQ_PORT_CAP_WRITE)
- || (caps & SND_SEQ_PORT_CAP_DUPLEX)))
- continue;
- else if ((snd_seq_client_info_get_type(cinfo) != SND_SEQ_USER_CLIENT)
- && ((type == SND_SEQ_PORT_SYSTEM_TIMER
- || type == SND_SEQ_PORT_SYSTEM_ANNOUNCE)))
- continue;
-
- const snd_seq_addr_t addr = *snd_seq_port_info_get_addr(pinfo);
-
- is_duplex = false;
-
- // FIXME: Should be CAP_SUBS_READ etc?
- 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);
- port_name = snd_seq_port_info_get_name(pinfo);
- boost::shared_ptr<PatchageModule> m;
-
- bool split = false;
-
- // Because there would be name conflicts, we must force a split if (stupid)
- // alsa duplex ports are present on the client
- if (is_duplex) {
- split = true;
- if (!_app->state_manager()->get_module_split(client_name, !is_application)) {
- need_refresh = true;
- _app->state_manager()->set_module_split(client_name, true);
- }
- } else {
- split = _app->state_manager()->get_module_split(client_name, !is_application);
- }
-
- /*cout << "SHOW: " << client_name << " : " << port_name
- << " is_application = " << is_application
- << " is_duplex = " << is_duplex
- << ", split = " << split << endl;*/
-
- // Application input/output ports go on the same module
- if (!split) {
- m = _app->canvas()->find_module(client_name, InputOutput);
- if (!m) {
- m = boost::shared_ptr<PatchageModule>(
- new PatchageModule(_app, client_name, InputOutput));
- m->load_location();
- _app->canvas()->add_item(m);
- }
-
- if (!m->get_port(port_name)) {
- if (!is_duplex) {
- m->add_port(create_port(m, port_name, is_input, addr));
- } else {
- m->add_port(create_port(m, port_name, true, addr));
- m->add_port(create_port(m, port_name, false, addr));
- }
- to_resize.insert(m);
- }
-
- } else { // non-application input/output ports (hw interface, etc) go on separate modules
- ModuleType type = InputOutput;
-
- // The 'application' hint isn't always set by clients, so this bit
- // is pretty nasty...
-
- if (!is_duplex) { // just one port to add
-
- type = ((is_input) ? Input : Output);
-
- m = _app->canvas()->find_module(client_name, type);
-
- if (!m) {
- m = boost::shared_ptr<PatchageModule>(
- new PatchageModule(_app, client_name, type));
- m->load_location();
- _app->canvas()->add_item(m);
- }
-
- if (!m->get_port(port_name)) {
- m->add_port(create_port(m, port_name, is_input, addr));
- to_resize.insert(m);
- }
-
- } else { // two ports to add
- type = Input;
-
- m = _app->canvas()->find_module(client_name, type);
-
- if (!m) {
- m = boost::shared_ptr<PatchageModule>(
- new PatchageModule(_app, client_name, type));
- m->load_location();
- _app->canvas()->add_item(m);
- }
-
- assert(m);
-
- if (!m->get_port(port_name)) {
- m->add_port(create_port(m, port_name, true, addr));
- to_resize.insert(m);
- }
-
- type = Output;
-
- m = _app->canvas()->find_module(client_name, type);
-
- if (!m) {
- m = boost::shared_ptr<PatchageModule>(
- new PatchageModule(_app, client_name, type));
- m->load_location();
- _app->canvas()->add_item(m);
- }
-
- if (!m->get_port(port_name)) {
- m->add_port(create_port(m, port_name, false, addr));
- to_resize.insert(m);
- }
- }
- }
- }
- }
-
- if (need_refresh) {
- _app->refresh();
- } else {
- for (set< boost::shared_ptr<PatchageModule> >::iterator i = to_resize.begin();
- i != to_resize.end(); ++i) {
- (*i)->resize();
+ create_port_view_internal(_app, *snd_seq_port_info_get_addr(pinfo), parent, port);
+ if (parent)
+ _app->enqueue_resize(parent);
}
}
}
@@ -496,15 +471,12 @@ AlsaDriver::refresh_main(void* me)
void
AlsaDriver::_refresh_main()
{
- // "Heavily influenced" from alsa-patch-bay
- // (C) 2002 Robert Ham, released under GPL
-
if (!create_refresh_port()) {
cerr << "Could not create Alsa listen port. Auto refreshing will not work." << endl;
return;
}
- int ret;
+ int ret = 0;
int nfds = snd_seq_poll_descriptors_count(_seq, POLLIN);
struct pollfd* pfds = new struct pollfd[nfds];
unsigned short* revents = new unsigned short[nfds];
@@ -528,12 +500,15 @@ AlsaDriver::_refresh_main()
continue;
}
+ snd_seq_port_info_t* pinfo;
+ snd_seq_port_info_alloca(&pinfo);
+ int caps = 0;
+
for (int i = 0; i < nfds; ++i) {
if (revents[i] > 0) {
snd_seq_event_t* ev;
snd_seq_event_input(_seq, &ev);
-
- if (ev == NULL)
+ if (!ev)
continue;
switch (ev->type) {
@@ -546,15 +521,26 @@ AlsaDriver::_refresh_main()
ev->data.connect.sender, ev->data.connect.dest));
break;
case SND_SEQ_EVENT_PORT_START:
+ snd_seq_port_info_set_client(pinfo, ev->data.addr.client);
+ caps = snd_seq_port_info_get_capability(pinfo);
+ _events.push(PatchageEvent(PatchageEvent::PORT_CREATION,
+ PortID(ev->data.addr, (caps & SND_SEQ_PORT_CAP_READ))));
+ break;
case SND_SEQ_EVENT_PORT_EXIT:
+ snd_seq_port_info_set_client(pinfo, ev->data.addr.client);
+ caps = snd_seq_port_info_get_capability(pinfo);
+ _events.push(PatchageEvent(PatchageEvent::PORT_DESTRUCTION,
+ PortID(ev->data.addr, (caps & SND_SEQ_PORT_CAP_READ))));
+ break;
+ // TODO: What should happen for these?
case SND_SEQ_EVENT_PORT_CHANGE:
case SND_SEQ_EVENT_CLIENT_START:
case SND_SEQ_EVENT_CLIENT_EXIT:
case SND_SEQ_EVENT_CLIENT_CHANGE:
case SND_SEQ_EVENT_RESET:
default:
- // FIXME: Ultra slow kludge, use proper find-grained events
- _events.push(PatchageEvent(PatchageEvent::REFRESH));
+ //_events.push(PatchageEvent(PatchageEvent::REFRESH));
+ break;
}
}
}
@@ -564,9 +550,3 @@ AlsaDriver::_refresh_main()
delete[] revents;
}
-
-void
-AlsaDriver::print_addr(snd_seq_addr_t addr)
-{
- cout << (int)addr.client << ":" << (int)addr.port << endl;
-}
diff --git a/src/AlsaDriver.hpp b/src/AlsaDriver.hpp
index c39f8c4..51e2b57 100644
--- a/src/AlsaDriver.hpp
+++ b/src/AlsaDriver.hpp
@@ -63,6 +63,19 @@ private:
bool create_refresh_port();
static void* refresh_main(void* me);
void _refresh_main();
+
+ boost::shared_ptr<PatchageModule>
+ find_or_create_module(
+ Patchage* patchage,
+ const std::string& client_name,
+ ModuleType type);
+
+ void
+ create_port_view_internal(
+ Patchage* patchage,
+ snd_seq_addr_t addr,
+ boost::shared_ptr<PatchageModule>& parent,
+ boost::shared_ptr<PatchagePort>& port);
boost::shared_ptr<PatchagePort> create_port(
boost::shared_ptr<PatchageModule> parent,
diff --git a/src/JackDbusDriver.cpp b/src/JackDbusDriver.cpp
index 0d0cf11..feb1923 100644
--- a/src/JackDbusDriver.cpp
+++ b/src/JackDbusDriver.cpp
@@ -111,7 +111,7 @@ JackDriver::destroy_all_ports()
if (module->ports().empty())
_app->canvas()->remove_item(module);
else
- module->resize();
+ _app->enqueue_resize();
}
}
@@ -555,7 +555,7 @@ JackDriver::add_port(
is_input,
_app->state_manager()->get_port_color(type))));
- module->resize();
+ _app->enqueue_resize(module);
}
@@ -620,7 +620,7 @@ JackDriver::remove_port(
_app->canvas()->remove_item(module);
module.reset();
} else {
- module->resize();
+ _app->enqueue_resize(module);
}
if (_app->canvas()->items().empty()) {
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index a0f1616..b98005c 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -135,7 +135,7 @@ JackDriver::destroy_all_ports()
if (module->ports().empty())
_app->canvas()->remove_item(module);
else
- module->resize();
+ _app->enqueue_resize(module);
}
}
@@ -170,26 +170,31 @@ JackDriver::create_port_view(Patchage* patchage,
boost::shared_ptr<PatchageModule> parent
= _app->canvas()->find_module(module_name, type);
+ bool resize = false;
+
if (!parent) {
parent = boost::shared_ptr<PatchageModule>(
new PatchageModule(patchage, module_name, type));
parent->load_location();
patchage->canvas()->add_item(parent);
parent->show();
+ resize = true;
}
boost::shared_ptr<PatchagePort> port
= boost::dynamic_pointer_cast<PatchagePort>(parent->get_port(port_name));
- if (port) {
- return port;
- } else {
+ if (!port) {
port = create_port(parent, jack_port);
port->show();
parent->add_port(port);
- parent->resize();
- return port;
+ resize = true;
}
+
+ if (resize)
+ _app->enqueue_resize(parent);
+
+ return port;
}
@@ -300,9 +305,10 @@ JackDriver::refresh()
continue;
}
- if (!m->get_port(jack_port_short_name(port))) {
+ if (!m->get_port(jack_port_short_name(port)))
m->add_port(create_port(m, port));
- }
+
+ _app->enqueue_resize(m);
}
// Add all connections
@@ -436,7 +442,6 @@ JackDriver::jack_client_registration_cb(const char* name, int registered, void*
jack_reset_max_delayed_usecs(me->_client);
- // FIXME: This sucks, not realtime :(
if (registered) {
me->_events.push(PatchageEvent(PatchageEvent::CLIENT_CREATION, name));
} else {
@@ -452,9 +457,6 @@ JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int registered, vo
JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
assert(me->_client);
- //jack_port_t* const port = jack_port_by_id(me->_client, port_id);
- //const string full_name = jack_port_name(port);
-
jack_reset_max_delayed_usecs(me->_client);
if (registered) {
diff --git a/src/Patchage.cpp b/src/Patchage.cpp
index 0a6d5e0..b00013b 100644
--- a/src/Patchage.cpp
+++ b/src/Patchage.cpp
@@ -23,6 +23,7 @@
#include <libglademm/xml.h>
#include <gtk/gtkwindow.h>
#include "raul/SharedPtr.hpp"
+#include "flowcanvas/Module.hpp"
#include "patchage-config.h"
#include "GladeFile.hpp"
@@ -342,6 +343,7 @@ Patchage::idle_callback()
_refresh = false;
}
+ flush_resize();
update_load();
return true;
@@ -414,9 +416,7 @@ Patchage::refresh()
_alsa_driver->refresh();
#endif
- for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
- (*i)->resize();
- }
+ flush_resize();
}
}
@@ -692,3 +692,23 @@ Patchage::buffer_size_changed()
#endif
}
+
+void
+Patchage::enqueue_resize(boost::shared_ptr<FlowCanvas::Module> module)
+{
+ if (module)
+ _pending_resize.insert(module);
+}
+
+
+void
+Patchage::flush_resize()
+{
+ for (set< boost::shared_ptr<FlowCanvas::Module> >::iterator i = _pending_resize.begin();
+ i != _pending_resize.end(); ++i) {
+ (*i)->resize();
+ }
+
+ _pending_resize.clear();
+}
+
diff --git a/src/Patchage.hpp b/src/Patchage.hpp
index 9aeedd0..a7b970f 100644
--- a/src/Patchage.hpp
+++ b/src/Patchage.hpp
@@ -19,21 +19,24 @@
#define PATCHAGE_PATCHAGE_HPP
#include <string>
+#include <set>
#include <boost/shared_ptr.hpp>
#include <libgnomecanvasmm.h>
#include <libglademm/xml.h>
#include "patchage-config.h"
#include "Widget.hpp"
-class PatchageCanvas;
-class JackDriver;
class AlsaDriver;
-class LashProxy;
-class StateManager;
-class JackSettingsDialog;
-class Session;
class DBus;
+class JackDriver;
+class JackSettingsDialog;
+class LashProxy;
+class PatchageCanvas;
class ProjectList;
+class Session;
+class StateManager;
+
+namespace FlowCanvas { class Module; }
class Patchage {
public:
@@ -73,7 +76,9 @@ public:
void status_msg(const std::string& msg);
void update_state();
void store_window_location();
-
+
+ void enqueue_resize(boost::shared_ptr<FlowCanvas::Module> module);
+ void flush_resize();
protected:
void connect_widgets();
@@ -118,6 +123,8 @@ protected:
boost::shared_ptr<PatchageCanvas> _canvas;
+ std::set< boost::shared_ptr<FlowCanvas::Module> > _pending_resize;
+
JackDriver* _jack_driver;
StateManager* _state_manager;
diff --git a/src/PatchageEvent.cpp b/src/PatchageEvent.cpp
index 63fa029..4fbefdf 100644
--- a/src/PatchageEvent.cpp
+++ b/src/PatchageEvent.cpp
@@ -68,9 +68,11 @@ PatchageEvent::execute(Patchage* patchage)
#endif
}
-
if (driver) {
- if ( ! driver->create_port_view(patchage, _port_1))
+ SharedPtr<PatchagePort> port = driver->create_port_view(patchage, _port_1);
+ if (port)
+ patchage->enqueue_resize(port->module().lock());
+ else
cerr << "Unable to create port view" << endl;
} else {
cerr << "ERROR: Create port with unknown port type" << endl;
@@ -85,6 +87,7 @@ PatchageEvent::execute(Patchage* patchage)
assert(module);
module->remove_port(port);
+ patchage->enqueue_resize(module);
port.reset();
// No empty modules (for now)
@@ -92,7 +95,7 @@ PatchageEvent::execute(Patchage* patchage)
patchage->canvas()->remove_item(module);
module.reset();
} else {
- module->resize();
+ patchage->enqueue_resize(module);
}
} else {
diff --git a/src/PatchageModule.hpp b/src/PatchageModule.hpp
index e21f67d..0eac76f 100644
--- a/src/PatchageModule.hpp
+++ b/src/PatchageModule.hpp
@@ -40,7 +40,6 @@ public:
, _app(app)
, _type(type)
{
-
}
virtual ~PatchageModule() { delete _menu; _menu = NULL; }