diff options
author | David Robillard <d@drobilla.net> | 2006-10-02 20:56:28 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2006-10-02 20:56:28 +0000 |
commit | 682a43546becbc86a210003846778ebb0c38718a (patch) | |
tree | 319e4b01347490d43a20e6ccc6b85cef94ee5288 /src/JackDriver.cpp | |
parent | 5812053fd22499251e2e2cedaa90fdd80c0d0988 (diff) | |
download | patchage-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.cpp | 266 |
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(); } |