summaryrefslogtreecommitdiffstats
path: root/src/JackDriver.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-10-02 20:56:28 +0000
committerDavid Robillard <d@drobilla.net>2006-10-02 20:56:28 +0000
commit682a43546becbc86a210003846778ebb0c38718a (patch)
tree319e4b01347490d43a20e6ccc6b85cef94ee5288 /src/JackDriver.cpp
parent5812053fd22499251e2e2cedaa90fdd80c0d0988 (diff)
downloadpatchage-682a43546becbc86a210003846778ebb0c38718a.tar.gz
patchage-682a43546becbc86a210003846778ebb0c38718a.tar.bz2
patchage-682a43546becbc86a210003846778ebb0c38718a.zip
boost::shared_ptr-ification of FlowCanvas.
Extreme performance enhancements in Patchage (eg don't redraw the whole canvas every time). Patchage work towards being a control centre. Broken commit (ingen doesn't even compile) for machine transfer, don't even bother trying this revision. git-svn-id: http://svn.drobilla.net/lad/patchage@147 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/JackDriver.cpp')
-rw-r--r--src/JackDriver.cpp266
1 files changed, 181 insertions, 85 deletions
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index c40e589..8147678 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -1,11 +1,11 @@
/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
*
- * Om is free software; you can redistribute it and/or modify it under the
+ * Patchage is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
- * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*
@@ -24,7 +24,7 @@
#include "Patchage.h"
#include "PatchageModule.h"
-using std::cerr; using std::endl; using std::cout;
+using std::cerr; using std::endl;
using std::string;
using namespace LibFlowCanvas;
@@ -49,30 +49,25 @@ JackDriver::~JackDriver()
void
JackDriver::attach(bool launch_daemon)
{
- cout << "Connecting to Jack... ";
- cout.flush();
-
- if (m_client != NULL) {
- cout << "already connected. " << endl;
+ // Already connected
+ if (m_client)
return;
- }
jack_options_t options = (!launch_daemon) ? JackNoStartServer : JackNullOption;
m_client = jack_client_open("Patchage", options, NULL);
if (m_client == NULL) {
- cout << "Failed" << endl;
+ m_app->status_message("[JACK] Unable to attach");
} else {
+ jack_on_shutdown(m_client, jack_shutdown_cb, this);
jack_set_port_registration_callback(m_client, jack_port_registration_cb, this);
jack_set_graph_order_callback(m_client, jack_graph_order_cb, this);
- jack_on_shutdown(m_client, jack_shutdown_cb, this);
- jack_activate(m_client);
-
- cout << "Connected" << endl;
-
- m_canvas->destroy();
-
m_is_dirty = true;
+
+ jack_activate(m_client);
+
+ signal_attached.emit();
+ m_app->status_message("[JACK] Attached");
}
}
@@ -84,33 +79,88 @@ JackDriver::detach()
jack_deactivate(m_client);
jack_client_close(m_client);
m_client = NULL;
- cout << "Disconnected from Jack" << endl;
+ signal_detached.emit();
+ destroy_all_ports();
+ m_app->status_message("[JACK] Detached");
+ }
+}
+
+
+/** Destroy all JACK (canvas) ports.
+ */
+void
+JackDriver::destroy_all_ports()
+{
+ ModuleMap modules = m_canvas->modules(); // copy
+ for (ModuleMap::iterator m = modules.begin(); m != modules.end(); ++m) {
+ PortVector ports = m->second->ports(); // copy
+ for (PortVector::iterator p = ports.begin(); p != ports.end(); ++p) {
+ boost::shared_ptr<PatchagePort> port = boost::dynamic_pointer_cast<PatchagePort>(*p);
+ if (port && port->type() == JACK_AUDIO || port->type() == JACK_MIDI) {
+ port.reset();
+ }
+ }
+
+ if (m->second->ports().empty())
+ m->second.reset();
}
}
+boost::shared_ptr<PatchagePort>
+JackDriver::create_port(boost::shared_ptr<PatchageModule> parent, jack_port_t* port)
+{
+ const char* const type_str = jack_port_type(port);
+ PortType port_type;
+ if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) {
+ port_type = JACK_MIDI;
+ } else if (!strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) {
+ port_type = JACK_AUDIO;
+ } else {
+ cerr << "WARNING: " << jack_port_name(port) << " has unknown type \'" << type_str << "\'" << endl;
+ return boost::shared_ptr<PatchagePort>();
+ }
+
+ boost::shared_ptr<PatchagePort> ret(
+ new PatchagePort(parent, port_type, jack_port_short_name(port),
+ (jack_port_flags(port) & JackPortIsInput),
+ m_app->state_manager()->get_port_color(port_type)));
+
+ return ret;
+}
+
+
/** Refresh all Jack audio ports/connections.
* To be called from GTK thread only.
*/
void
JackDriver::refresh()
{
- if (m_client == NULL)
+ m_mutex.lock();
+
+ if (m_client == NULL) {
+ // Shutdown
+ if (m_is_dirty) {
+ signal_detached.emit();
+ destroy_all_ports();
+ }
+ m_is_dirty = false;
+ m_mutex.unlock();
return;
-
+ }
+
const char** ports;
jack_port_t* port;
-
+
ports = jack_get_ports(m_client, NULL, NULL, 0); // get all existing ports
string client1_name;
string port1_name;
string client2_name;
string port2_name;
- PatchageModule* m = NULL;
-
+
// Add all ports
- if (ports != NULL)
+ if (ports)
for (int i=0; ports[i]; ++i) {
port = jack_port_by_name(m_client, ports[i]);
client1_name = ports[i];
@@ -118,9 +168,9 @@ JackDriver::refresh()
ModuleType type = InputOutput;
//if (m_app->state_manager()->get_module_split(client1_name)
- // || jack_port_flags(port) & JackPortIsTerminal) {
+ // || jack_port_flags(port) & JackPortIsTerminal)
if (m_app->state_manager()->get_module_split(client1_name,
- (jack_port_flags(port) & JackPortIsTerminal))) {
+ (jack_port_flags(port) & JackPortIsTerminal))) {
if (jack_port_flags(port) & JackPortIsInput) {
type = Input;
} else {
@@ -128,56 +178,84 @@ JackDriver::refresh()
}
}
- m = (PatchageModule*)m_canvas->find_module(client1_name, type);
+ boost::shared_ptr<PatchageModule> m = m_canvas->find_module(client1_name, type);
- if (m == NULL) {
- m = new PatchageModule(m_app, client1_name, type);
+ if (!m) {
+ m = boost::shared_ptr<PatchageModule>(new PatchageModule(m_app, client1_name, type));
m->load_location();
m->store_location();
- m->show();
+ m_app->canvas()->add_module(m);
}
-
+
// FIXME: leak? jack docs don't say
const char* const type_str = jack_port_type(port);
- PortType port_type = JACK_AUDIO;
- if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE))
+ PortType port_type;
+ if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) {
port_type = JACK_MIDI;
- else if (strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE))
- throw "Unknown JACK port type?";
+ } else if (!strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) {
+ port_type = JACK_AUDIO;
+ } else {
+ cerr << "WARNING: " << ports[i] << " has unknown type \'" << type_str << "\'" << endl;
+ continue;
+ }
- m->add_patchage_port(jack_port_short_name(port),
- (jack_port_flags(port) & JackPortIsInput),
- port_type);
+ if (!m->get_port(jack_port_short_name(port))) {
+ m->add_port(create_port(m, port));
+ }
+
+ m->resize();
}
+
+ // Remove any since-removed ports
+ for (list<string>::iterator i = m_removed_ports.begin(); i != m_removed_ports.end(); ++i) {
+ const string module_name = (*i).substr(0, i->find(":"));
+ const string port_name = (*i).substr(i->find(":")+1);
+
+ for (ModuleMap::iterator m = m_canvas->modules().begin(); m != m_canvas->modules().end(); ++m) {
+ if (m->second->name() == module_name)
+ m->second->remove_port(port_name);
+ }
+ }
+
+
// Add all connections
- if (ports != NULL) {
- for (int i=0; ports[i]; ++i) {
- port = jack_port_by_name(m_client, ports[i]);
- const char** connected_ports = jack_port_get_all_connections(m_client, port);
-
- if (connected_ports != NULL)
+ if (ports)
+ for (int i=0; ports[i]; ++i) {
+ port = jack_port_by_name(m_client, ports[i]);
+ const char** connected_ports = jack_port_get_all_connections(m_client, port);
+
+ if (connected_ports) {
for (int j=0; connected_ports[j]; ++j) {
client1_name = ports[i];
port1_name = client1_name.substr(client1_name.find(':')+1);
client1_name = client1_name.substr(0, client1_name.find(':'));
-
+
client2_name = connected_ports[j];
port2_name = client2_name.substr(client2_name.find(':')+1);
client2_name = client2_name.substr(0, client2_name.find(':'));
-
- Port* const port1 = m_canvas->get_port(client1_name, port1_name);
- Port* const port2 = m_canvas->get_port(client2_name, port2_name);
-
- if (port1 && port2)
- m_canvas->add_connection(port1, port2);
+
+ boost::shared_ptr<Port> port1 = m_canvas->get_port(client1_name, port1_name);
+ boost::shared_ptr<Port> port2 = m_canvas->get_port(client2_name, port2_name);
+
+ if (port1 && port2) {
+ boost::shared_ptr<Connection> existing = m_canvas->get_connection(port1, port2);
+ if (existing) {
+ existing->set_flagged(false);
+ } else {
+ m_canvas->add_connection(port1, port2);
+ }
+ }
}
+
free(connected_ports);
- }
- free(ports);
+ }
}
+ free(ports);
undirty();
+
+ m_mutex.unlock();
}
@@ -186,22 +264,19 @@ JackDriver::refresh()
* \return Whether connection succeeded.
*/
bool
-JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+JackDriver::connect(boost::shared_ptr<PatchagePort> src_port, boost::shared_ptr<PatchagePort> dst_port)
{
if (m_client == NULL)
return false;
int result = jack_connect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
- string msg;
-
- if (result == 0) {
- msg = "Successfully connected jack ports";
- } else {
- msg = "Unable to connect ";
- msg += src_port->full_name() + " -> " + dst_port->full_name();
- }
- m_app->status_message(msg);
+ if (result == 0)
+ m_app->status_message(string("[JACK] Connected ")
+ + src_port->full_name() + " -> " + dst_port->full_name());
+ else
+ m_app->status_message(string("[JACK] Unable to connect ")
+ + src_port->full_name() + " -> " + dst_port->full_name());
return (!result);
}
@@ -212,53 +287,74 @@ JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons
* \return Whether disconnection succeeded.
*/
bool
-JackDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+JackDriver::disconnect(boost::shared_ptr<PatchagePort> const src_port, boost::shared_ptr<PatchagePort> const dst_port)
{
if (m_client == NULL)
return false;
int result = jack_disconnect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
- string msg;
-
- if (result == 0) {
- msg = "Successfully disconnected jack ports";
- } else {
- msg = "Unable to disconnect ";
- msg += src_port->full_name() + " -> " + dst_port->full_name();
- }
- m_app->status_message(msg);
+ if (result == 0)
+ m_app->status_message(string("[JACK] Disconnected ")
+ + src_port->full_name() + " -> " + dst_port->full_name());
+ else
+ m_app->status_message(string("[JACK] Unable to disconnect ")
+ + src_port->full_name() + " -> " + dst_port->full_name());
return (!result);
}
void
-JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int registered, void* me)
+JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int /*registered*/, void* jack_driver)
{
- assert(me != NULL);
- assert(((JackDriver*)me)->m_client != NULL);
- ((JackDriver*)me)->m_is_dirty = true;
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->m_client);
+
+ jack_port_t* const port = jack_port_by_id(me->m_client, port_id);
+ const string full_name = jack_port_name(port);
+
+ //(me->m_mutex).lock();
+
+ /*if (registered) {
+ me->m_added_ports.push_back(full_name);
+ } else {
+ me->m_removed_ports.push_back(full_name);
+ }*/
+
+ me->m_is_dirty = true;
+
+ //(me->m_mutex).unlock();
}
int
-JackDriver::jack_graph_order_cb(void* me)
+JackDriver::jack_graph_order_cb(void* jack_driver)
{
- assert(me != NULL);
- assert(((JackDriver*)me)->m_client != NULL);
- ((JackDriver*)me)->m_is_dirty = true;
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->m_client);
+
+ //(me->m_mutex).lock();
+ me->m_is_dirty = true;
+ //(me->m_mutex).unlock();
return 0;
}
void
-JackDriver::jack_shutdown_cb(void* me)
+JackDriver::jack_shutdown_cb(void* jack_driver)
{
- assert(me != NULL);
- ((JackDriver*)me)->m_client = NULL;
- ((JackDriver*)me)->m_is_dirty = true;
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->m_client);
+
+ //(me->m_mutex).lock();
+ me->m_client = NULL;
+ me->m_is_dirty = true;
+ //(me->m_mutex).unlock();
}