From 682a43546becbc86a210003846778ebb0c38718a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 2 Oct 2006 20:56:28 +0000 Subject: 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 --- src/AlsaDriver.cpp | 163 +++++++++----- src/AlsaDriver.h | 16 +- src/Driver.h | 26 ++- src/JackDriver.cpp | 266 +++++++++++++++-------- src/JackDriver.h | 31 ++- src/LashDriver.cpp | 20 +- src/LashDriver.h | 10 +- src/Makefile.am | 1 + src/Patchage.cpp | 231 ++++++++++---------- src/Patchage.h | 24 +-- src/PatchageFlowCanvas.cpp | 63 +++--- src/PatchageFlowCanvas.h | 8 +- src/PatchageModule.h | 12 +- src/PatchagePort.h | 11 +- src/StateManager.cpp | 4 +- src/StateManager.h | 4 +- src/main.cpp | 10 +- src/patchage.glade | 522 ++++++++++++++++++++++++--------------------- 18 files changed, 811 insertions(+), 611 deletions(-) (limited to 'src') diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 909a710..43ee297 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.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. * @@ -49,25 +49,24 @@ AlsaDriver::~AlsaDriver() * @a launch_daemon is ignored, as ALSA has no daemon to launch/connect to. */ void -AlsaDriver::attach(bool launch_daemon) +AlsaDriver::attach(bool /*launch_daemon*/) { - cout << "Connecting to Alsa... "; - cout.flush(); - int ret = snd_seq_open(&m_seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK); if (ret) { - cout << "Failed" << endl; + m_app->status_message("[ALSA] Unable to attach"); m_seq = NULL; } else { - cout << "Connected" << endl; + m_app->status_message("[ALSA] Attached"); snd_seq_set_client_name(m_seq, "Patchage"); ret = pthread_create(&m_refresh_thread, NULL, &AlsaDriver::refresh_main, this); if (ret) cerr << "Couldn't start refresh thread" << endl; + + signal_attached.emit(); } } @@ -80,7 +79,8 @@ AlsaDriver::detach() pthread_join(m_refresh_thread, NULL); snd_seq_close(m_seq); m_seq = NULL; - cout << "Disconnected from Alsa" << endl; + signal_detached.emit(); + m_app->status_message("[ALSA] Detached"); } } @@ -102,6 +102,18 @@ AlsaDriver::refresh() } +boost::shared_ptr +AlsaDriver::create_port(boost::shared_ptr parent, + const string& name, bool is_input, snd_seq_addr_t addr) +{ + boost::shared_ptr ret( + new PatchagePort(parent, ALSA_MIDI, name, is_input, + m_app->state_manager()->get_port_color(ALSA_MIDI))); + ret->alsa_addr(addr); + return ret; +} + + /** Refresh all Alsa Midi ports. */ void @@ -159,7 +171,7 @@ AlsaDriver::refresh_ports() is_application = (type & SND_SEQ_PORT_TYPE_APPLICATION); port_name = snd_seq_port_info_get_name(pinfo); - PatchageModule* m = NULL; + boost::shared_ptr m; //cout << client_name << " : " << port_name << " is_application = " << is_application // << " is_duplex = " << is_duplex << endl; @@ -168,22 +180,23 @@ AlsaDriver::refresh_ports() // Application input/output ports go on the same module if (!split) { - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); + if (!m) { + m = boost::shared_ptr(new PatchageModule(m_app, client_name, InputOutput)); m->load_location(); m->store_location(); - m->show(); + m_app->canvas()->add_module(m); } - if (!is_duplex) { - m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr); - } else { - m->add_patchage_port(port_name, true, ALSA_MIDI, addr); - m->add_patchage_port(port_name, false, ALSA_MIDI, addr); + 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)); + } } } else { // non-application input/output ports (hw interface, etc) go on separate modules - PatchageModule* m = NULL; ModuleType type = InputOutput; // The 'application' hint isn't always set by clients, so this bit @@ -194,46 +207,61 @@ AlsaDriver::refresh_ports() else type = Output; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr( + new PatchageModule(m_app, client_name, type)); m->load_location(); m->store_location(); + m_app->canvas()->add_module(m); } - m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr); + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, is_input, addr)); } else { // two ports to add type = Input; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr( + new PatchageModule(m_app, client_name, type)); m->load_location(); m->store_location(); } - m->add_patchage_port(port_name, true, ALSA_MIDI, addr); + + assert(m); + + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, true, addr)); type = Output; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr( + new PatchageModule(m_app, client_name, type)); + m->load_location(); m->store_location(); } - m->add_patchage_port(port_name, false, ALSA_MIDI, addr); + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, false, addr)); } - m->show(); + m->resize(); + m_app->canvas()->add_module(m); } } } @@ -248,16 +276,18 @@ AlsaDriver::refresh_connections() assert(is_attached()); assert(m_seq); - PatchageModule* m = NULL; - PatchagePort* p = NULL; + boost::shared_ptr m; + boost::shared_ptr p; for (ModuleMap::iterator i = m_canvas->modules().begin(); i != m_canvas->modules().end(); ++i) { - m = (PatchageModule*)((*i).second); - for (PortList::iterator j = m->ports().begin(); j != m->ports().end(); ++j) { - p = (PatchagePort*)(*j); - if (p->type() == ALSA_MIDI) - add_connections(p); + m = boost::dynamic_pointer_cast((*i).second); + if (m) { + for (PortVector::const_iterator j = m->ports().begin(); j != m->ports().end(); ++j) { + p = boost::dynamic_pointer_cast(*j); + if (p->type() == ALSA_MIDI) + add_connections(p); + } } } } @@ -266,13 +296,13 @@ AlsaDriver::refresh_connections() /** Add all connections for the given port. */ void -AlsaDriver::add_connections(PatchagePort* port) +AlsaDriver::add_connections(boost::shared_ptr port) { assert(is_attached()); assert(m_seq); - const snd_seq_addr_t* addr = port->alsa_addr(); - PatchagePort* connected_port = NULL; + const snd_seq_addr_t* addr = port->alsa_addr(); + boost::shared_ptr connected_port; // Fix a problem with duplex->duplex connections (would show up twice) // No sense doing them all twice anyway.. @@ -287,10 +317,15 @@ AlsaDriver::add_connections(PatchagePort* port) while(!snd_seq_query_port_subscribers(m_seq, subsinfo)) { const snd_seq_addr_t* connected_addr = snd_seq_query_subscribe_get_addr(subsinfo); - connected_port = m_canvas->find_port(connected_addr, !port->is_input()); - - if (connected_port != NULL) { - m_canvas->add_connection(port, connected_port); + connected_port = m_canvas->find_port(connected_addr); + + if (connected_port) { + boost::shared_ptr existing = m_canvas->get_connection(port, connected_port); + if (existing) { + existing->set_flagged(false); + } else { + m_canvas->add_connection(port, connected_port); + } } snd_seq_query_subscribe_set_index(subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1); @@ -304,12 +339,12 @@ AlsaDriver::add_connections(PatchagePort* port) * \return Whether connection succeeded. */ bool -AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +AlsaDriver::connect(boost::shared_ptr src_port, boost::shared_ptr dst_port) { const snd_seq_addr_t* src = src_port->alsa_addr(); const snd_seq_addr_t* dst = dst_port->alsa_addr(); - bool result = false; + bool result = true; if (src && dst) { snd_seq_port_subscribe_t* subs; @@ -332,6 +367,13 @@ AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons result = false; } } + + if (result) + m_app->status_message(string("[ALSA] Connected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[ALSA] Unable to connect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } @@ -342,12 +384,12 @@ AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons * \return Whether disconnection succeeded. */ bool -AlsaDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +AlsaDriver::disconnect(boost::shared_ptr src_port, boost::shared_ptr dst_port) { const snd_seq_addr_t* src = src_port->alsa_addr(); const snd_seq_addr_t* dst = dst_port->alsa_addr(); - bool result = false; + bool result = true; snd_seq_port_subscribe_t* subs; snd_seq_port_subscribe_malloc(&subs); @@ -368,6 +410,13 @@ AlsaDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* c cerr << "Alsa unsubscription failed: " << snd_strerror(ret) << endl; result = false; } + + if (result) + m_app->status_message(string("[ALSA] Disconnected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[ALSA] Unable to disconnect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } diff --git a/src/AlsaDriver.h b/src/AlsaDriver.h index d6e910f..27ddee9 100644 --- a/src/AlsaDriver.h +++ b/src/AlsaDriver.h @@ -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. * @@ -45,8 +45,11 @@ public: void refresh(); - bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port); + bool connect(boost::shared_ptr src_port, + boost::shared_ptr dst_port); + + bool disconnect(boost::shared_ptr src_port, + boost::shared_ptr dst_port); PatchageFlowCanvas* canvas() { return m_canvas; } @@ -54,12 +57,15 @@ private: void refresh_ports(); void refresh_connections(); - void add_connections(PatchagePort* port); + void add_connections(boost::shared_ptr port); bool create_refresh_port(); static void* refresh_main(void* me); void m_refresh_main(); + boost::shared_ptr create_port(boost::shared_ptr parent, + const string& name, bool is_input, snd_seq_addr_t addr); + Patchage* m_app; PatchageFlowCanvas* m_canvas; diff --git a/src/Driver.h b/src/Driver.h index 1b7ad80..1945286 100644 --- a/src/Driver.h +++ b/src/Driver.h @@ -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. * @@ -17,6 +17,9 @@ #ifndef DRIVER_H #define DRIVER_H +#include +#include + class PatchagePort; /** Trival driver base class */ @@ -30,19 +33,20 @@ public: virtual void refresh() = 0; - virtual bool connect(const PatchagePort* src_port, - const PatchagePort* dst_port) - { return false; } + virtual bool connect(boost::shared_ptr src_port, + boost::shared_ptr dst_port) = 0; - virtual bool disconnect(const PatchagePort* src_port, - const PatchagePort* dst_port) - { return false; } + virtual bool disconnect(boost::shared_ptr src_port, + boost::shared_ptr dst_port) = 0; - /** Returns whether or not a refresh is required. */ - bool is_dirty() const { return m_is_dirty; } + /** Returns whether or not a refresh is required (pending). */ + inline bool is_dirty() const { return m_is_dirty; } /** Clear 'dirty' status after a refresh. */ - void undirty() { m_is_dirty = false; } + inline void undirty() { m_is_dirty = false; } + + sigc::signal signal_attached; + sigc::signal signal_detached; protected: Driver() : m_is_dirty(false) {} 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 port = boost::dynamic_pointer_cast(*p); + if (port && port->type() == JACK_AUDIO || port->type() == JACK_MIDI) { + port.reset(); + } + } + + if (m->second->ports().empty()) + m->second.reset(); } } +boost::shared_ptr +JackDriver::create_port(boost::shared_ptr 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(); + } + + boost::shared_ptr 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 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(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::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 port1 = m_canvas->get_port(client1_name, port1_name); + boost::shared_ptr port2 = m_canvas->get_port(client2_name, port2_name); + + if (port1 && port2) { + boost::shared_ptr 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 src_port, boost::shared_ptr 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 const src_port, boost::shared_ptr 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(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(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(jack_driver); + assert(me->m_client); + + //(me->m_mutex).lock(); + me->m_client = NULL; + me->m_is_dirty = true; + //(me->m_mutex).unlock(); } diff --git a/src/JackDriver.h b/src/JackDriver.h index 6b69900..db74f77 100644 --- a/src/JackDriver.h +++ b/src/JackDriver.h @@ -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. * @@ -18,12 +18,15 @@ #define JACKDRIVER_H #include -#include #include +#include +#include +#include "Mutex.h" #include "Driver.h" class Patchage; class PatchageFlowCanvas; class PatchagePort; +class PatchageModule; using std::string; @@ -45,13 +48,11 @@ public: bool is_attached() const { return (m_client != NULL); } void refresh(); - bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - /*bool connect(const string& src_module_name, const string& src_port_name, - const string& dst_module_name, const string& dest_port_name); - - bool disconnect(const string& src_module_name, const string& src_port_name, - const string& dst_module_name, const string& dest_port_name);*/ + bool connect(boost::shared_ptr src, + boost::shared_ptr dst); + + bool disconnect(boost::shared_ptr src, + boost::shared_ptr dst); private: Patchage* m_app; @@ -59,6 +60,16 @@ private: jack_client_t* m_client; + Mutex m_mutex; + + list m_added_ports; + list m_removed_ports; + + boost::shared_ptr create_port(boost::shared_ptr parent, + jack_port_t* port); + + void destroy_all_ports(); + static void jack_port_registration_cb(jack_port_id_t port_id, int registered, void* controller); static int jack_graph_order_cb(void* controller); static void jack_shutdown_cb(void* controller); diff --git a/src/LashDriver.cpp b/src/LashDriver.cpp index c4a89b2..7989aa9 100644 --- a/src/LashDriver.cpp +++ b/src/LashDriver.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. * @@ -44,25 +44,22 @@ LashDriver::~LashDriver() void LashDriver::attach(bool launch_daemon) { - cout << "Connecting to Lash... "; - cout.flush(); - - if (m_client != NULL) { - cout << "already connected." << endl; + // Already connected + if (m_client) return; - } int lash_flags = LASH_Config_File; if (launch_daemon) lash_flags |= LASH_No_Start_Server; m_client = lash_init(m_args, PACKAGE_NAME, lash_flags, LASH_PROTOCOL(2, 0)); if (m_client == NULL) { - cout << "Failed. Session management will not occur." << endl; + m_app->status_message("[LASH] Unable to attach to server"); } else { lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); lash_event_set_string(event, "Patchage"); lash_send_event(m_client, event); - cout << "Connected" << endl; + signal_attached.emit(); + m_app->status_message("[LASH] Attached"); } } @@ -72,7 +69,8 @@ LashDriver::detach() { // FIXME: send some notification that we're gone?? m_client = NULL; - cout << "Disconnected from Lash" << endl; + m_app->status_message("[LASH] Detached"); + signal_detached.emit(); } diff --git a/src/LashDriver.h b/src/LashDriver.h index 742c249..9f361d7 100644 --- a/src/LashDriver.h +++ b/src/LashDriver.h @@ -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. * @@ -32,6 +32,12 @@ public: void detach(); bool is_attached() const { return lash_enabled(m_client); } + + bool connect(boost::shared_ptr, boost::shared_ptr) + { return false; } + + bool disconnect(boost::shared_ptr, boost::shared_ptr) + { return false; } void refresh() {} diff --git a/src/Makefile.am b/src/Makefile.am index 6e6eb5f..81529ab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ dist_sharefiles_DATA = patchage.glade bin_PROGRAMS = patchage patchage_SOURCES = \ main.cpp \ + Mutex.h \ Patchage.h \ Patchage.cpp \ StateManager.h \ diff --git a/src/Patchage.cpp b/src/Patchage.cpp index d6e3a55..0a37e58 100644 --- a/src/Patchage.cpp +++ b/src/Patchage.cpp @@ -1,11 +1,11 @@ -/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. +/* This file is part of Patchage. Copyright (C) 2006 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. * @@ -58,7 +58,7 @@ Patchage::Patchage(int argc, char** argv) m_lash_driver = new LashDriver(this, argc, argv); #endif - Glib::RefPtr refXml; + Glib::RefPtr xml; // Check for the .glade file in current directory string glade_filename = "./patchage.glade"; @@ -77,57 +77,59 @@ Patchage::Patchage(int argc, char** argv) } try { - refXml = Gnome::Glade::Xml::create(glade_filename); + xml = Gnome::Glade::Xml::create(glade_filename); } catch(const Gnome::Glade::XmlError& ex) { std::cerr << ex.what() << std::endl; throw; } - refXml->get_widget("patchage_win", m_main_window); - refXml->get_widget("about_win", m_about_window); - refXml->get_widget("about_project_label", m_about_project_label); - refXml->get_widget("launch_jack_menuitem", m_menu_jack_launch); - refXml->get_widget("connect_to_jack_menuitem", m_menu_jack_connect); - refXml->get_widget("disconnect_from_jack_menuitem", m_menu_jack_disconnect); + xml->get_widget("patchage_win", m_main_window); + xml->get_widget("about_win", m_about_window); + xml->get_widget("launch_jack_menuitem", m_menu_jack_launch); + xml->get_widget("connect_to_jack_menuitem", m_menu_jack_connect); + xml->get_widget("disconnect_from_jack_menuitem", m_menu_jack_disconnect); #ifdef HAVE_LASH - refXml->get_widget("launch_lash_menuitem", m_menu_lash_launch); - refXml->get_widget("connect_to_lash_menuitem", m_menu_lash_connect); - refXml->get_widget("disconnect_from_lash_menuitem", m_menu_lash_disconnect); + xml->get_widget("launch_lash_menuitem", m_menu_lash_launch); + xml->get_widget("connect_to_lash_menuitem", m_menu_lash_connect); + xml->get_widget("disconnect_from_lash_menuitem", m_menu_lash_disconnect); #endif #ifdef HAVE_ALSA - refXml->get_widget("connect_to_alsa_menuitem", m_menu_alsa_connect); - refXml->get_widget("disconnect_from_alsa_menuitem", m_menu_alsa_disconnect); + xml->get_widget("connect_to_alsa_menuitem", m_menu_alsa_connect); + xml->get_widget("disconnect_from_alsa_menuitem", m_menu_alsa_disconnect); #endif - refXml->get_widget("file_save_menuitem", m_menu_file_save); - refXml->get_widget("file_quit_menuitem", m_menu_file_quit); - refXml->get_widget("view_refresh_menuitem", m_menu_view_refresh); - refXml->get_widget("help_about_menuitem", m_menu_help_about); - refXml->get_widget("canvas_scrolledwindow", m_canvas_scrolledwindow); - refXml->get_widget("zoom_scale", m_zoom_slider); - refXml->get_widget("about_close_button", m_about_close_button); - refXml->get_widget("status_lab", m_status_label); + xml->get_widget("store_positions_menuitem", m_menu_store_positions); + xml->get_widget("file_quit_menuitem", m_menu_file_quit); + xml->get_widget("view_refresh_menuitem", m_menu_view_refresh); + xml->get_widget("help_about_menuitem", m_menu_help_about); + xml->get_widget("canvas_scrolledwindow", m_canvas_scrolledwindow); + xml->get_widget("zoom_scale", m_zoom_slider); + xml->get_widget("status_text", m_status_text); + xml->get_widget("main_paned", m_main_paned); + xml->get_widget("zoom_full_but", m_zoom_full_button); + xml->get_widget("zoom_normal_but", m_zoom_normal_button); - m_main_window->resize( - static_cast(m_state_manager->get_window_size().x), - static_cast(m_state_manager->get_window_size().y)); - - m_main_window->move( - static_cast(m_state_manager->get_window_location().x), - static_cast(m_state_manager->get_window_location().y)); + update_state(); m_canvas_scrolledwindow->add(*m_canvas); //m_canvas_scrolledwindow->signal_event().connect(sigc::mem_fun(m_canvas, &FlowCanvas::scroll_event_handler)); m_canvas->scroll_to(static_cast(m_canvas->width()/2 - 320), static_cast(m_canvas->height()/2 - 240)); // FIXME: hardcoded - m_canvas->show(); - // Idle callback, check if we need to refresh (every 250msec) - Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 250); + // Idle callback, check if we need to refresh + Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 100); + + m_zoom_slider->signal_value_changed().connect(sigc::mem_fun(this, &Patchage::zoom_changed)); + m_zoom_normal_button->signal_clicked().connect(sigc::bind( + sigc::mem_fun(this, &Patchage::zoom), 1.0)); + + m_menu_jack_launch->signal_activate().connect(sigc::bind( + sigc::mem_fun(m_jack_driver, &JackDriver::attach), true)); + + m_menu_jack_connect->signal_activate().connect(sigc::bind( + sigc::mem_fun(m_jack_driver, &JackDriver::attach), false)); - m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &Patchage::zoom_changed)); - m_menu_jack_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_launch)); - m_menu_jack_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_connect)); - m_menu_jack_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_jack_disconnect)); + m_menu_jack_disconnect->signal_activate().connect(sigc::mem_fun(m_jack_driver, &JackDriver::detach)); + #ifdef HAVE_LASH m_menu_lash_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_launch)); m_menu_lash_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_connect)); @@ -135,26 +137,29 @@ Patchage::Patchage(int argc, char** argv) #endif m_menu_alsa_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_alsa_connect)); m_menu_alsa_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_alsa_disconnect)); - m_menu_file_save->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_save)); + m_menu_store_positions->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_store_positions)); m_menu_file_quit->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_quit)); m_menu_view_refresh->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_view_refresh)); m_menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_help_about)); - m_about_close_button->signal_clicked().connect( sigc::mem_fun(this, &Patchage::close_about)); - //_about_project_label->use_markup(true); - m_about_project_label->set_markup("Patchage " PACKAGE_VERSION ""); + attach_menu_items(); + m_main_paned->set_position(m_main_paned->get_height() - 20); + + m_canvas->show(); } Patchage::~Patchage() { + delete m_jack_driver; +#ifdef HAVE_ALSA + delete m_alsa_driver; +#endif #ifdef HAVE_LASH delete m_lash_driver; #endif - delete m_jack_driver; - delete m_alsa_driver; - delete m_canvas; delete m_state_manager; + delete m_canvas; } @@ -170,7 +175,6 @@ Patchage::attach() m_alsa_driver->attach(); #endif - update_menu_items(); menu_view_refresh(); } @@ -178,19 +182,20 @@ Patchage::attach() bool Patchage::idle_callback() { - // FIXME: no need to destroy the whole canvas every time - if (m_refresh || (m_jack_driver && m_jack_driver->is_dirty()) + bool refresh = m_refresh; + + refresh = refresh || (m_jack_driver && m_jack_driver->is_dirty()); #ifdef HAVE_ALSA - || (m_alsa_driver && m_alsa_driver->is_dirty()) + refresh = refresh || (m_alsa_driver && m_alsa_driver->is_dirty()); #endif - ) { - m_canvas->destroy(); + + if (refresh) { + m_canvas->flag_all_connections(); + m_jack_driver->refresh(); #ifdef HAVE_ALSA m_alsa_driver->refresh(); #endif - update_menu_items(); - m_refresh = false; } #ifdef HAVE_LASH @@ -198,20 +203,30 @@ Patchage::idle_callback() m_lash_driver->process_events(); #endif + if (refresh) { + m_canvas->destroy_all_flagged_connections(); + m_refresh = false; + } + return true; } void -Patchage::zoom_changed() +Patchage::zoom(double z) { - const double z = m_zoom_slider->get_value(); - m_canvas->set_zoom(z); m_state_manager->set_zoom(z); } +void +Patchage::zoom_changed() +{ + zoom(m_zoom_slider->get_value()); +} + + void Patchage::update_state() { @@ -236,10 +251,12 @@ Patchage::update_state() void Patchage::status_message(const string& msg) { - m_status_label->set_text(msg); -} - + if (m_status_text->get_buffer()->size() > 0) + m_status_text->get_buffer()->insert(m_status_text->get_buffer()->end(), "\n"); + m_status_text->get_buffer()->insert(m_status_text->get_buffer()->end(), msg); + m_status_text->scroll_to_mark(m_status_text->get_buffer()->get_insert(), 0); +} /** Update the sensitivity status of menus to reflect the present. @@ -247,61 +264,53 @@ Patchage::status_message(const string& msg) * (eg. disable "Connect to Jack" when Patchage is already connected to Jack) */ void -Patchage::update_menu_items() +Patchage::attach_menu_items() { - // Update Jack menu items - const bool jack_attached = m_jack_driver->is_attached(); - m_menu_jack_launch->set_sensitive(!jack_attached); - m_menu_jack_connect->set_sensitive(!jack_attached); - m_menu_jack_disconnect->set_sensitive(jack_attached); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_launch, &Gtk::MenuItem::set_sensitive), false)); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_connect, &Gtk::MenuItem::set_sensitive), false)); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_disconnect, &Gtk::MenuItem::set_sensitive), true)); - // Update Lash menu items -#ifdef HAVE_LASH - const bool lash_attached = m_lash_driver->is_attached(); - m_menu_lash_launch->set_sensitive(!lash_attached); - m_menu_lash_connect->set_sensitive(!lash_attached); - m_menu_lash_disconnect->set_sensitive(lash_attached); -#endif - -#ifdef HAVE_ALSA - // Update Alsa menu items - const bool alsa_attached = m_alsa_driver->is_attached(); - m_menu_alsa_connect->set_sensitive(!alsa_attached); - m_menu_alsa_disconnect->set_sensitive(alsa_attached); -#endif -} - - -void -Patchage::menu_jack_launch() -{ - m_jack_driver->attach(true); - update_menu_items(); -} - - -void -Patchage::menu_jack_connect() -{ - m_jack_driver->attach(false); - update_menu_items(); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_launch, &Gtk::MenuItem::set_sensitive), true)); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_connect, &Gtk::MenuItem::set_sensitive), true)); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_disconnect, &Gtk::MenuItem::set_sensitive), false)); + + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), false)); + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_connect, &Gtk::MenuItem::set_sensitive), false)); + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_disconnect, &Gtk::MenuItem::set_sensitive), true)); + + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), true)); + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_connect, &Gtk::MenuItem::set_sensitive), true)); + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_disconnect, &Gtk::MenuItem::set_sensitive), false)); + + m_alsa_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_connect, &Gtk::MenuItem::set_sensitive), false)); + m_alsa_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_disconnect, &Gtk::MenuItem::set_sensitive), true)); + + m_alsa_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_connect, &Gtk::MenuItem::set_sensitive), true)); + m_alsa_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_disconnect, &Gtk::MenuItem::set_sensitive), false)); } -void -Patchage::menu_jack_disconnect() -{ - m_jack_driver->detach(); - menu_view_refresh(); - update_menu_items(); -} - #ifdef HAVE_LASH void Patchage::menu_lash_launch() { m_lash_driver->attach(true); - update_menu_items(); } @@ -309,7 +318,6 @@ void Patchage::menu_lash_connect() { m_lash_driver->attach(false); - update_menu_items(); } @@ -317,7 +325,6 @@ void Patchage::menu_lash_disconnect() { m_lash_driver->detach(); - update_menu_items(); } #endif @@ -326,7 +333,6 @@ void Patchage::menu_alsa_connect() { m_alsa_driver->attach(false); - update_menu_items(); } @@ -335,12 +341,11 @@ Patchage::menu_alsa_disconnect() { m_alsa_driver->detach(); menu_view_refresh(); - update_menu_items(); } #endif void -Patchage::menu_file_save() +Patchage::menu_store_positions() { store_window_location(); m_state_manager->save(m_settings_filename); @@ -363,7 +368,6 @@ Patchage::menu_view_refresh() { assert(m_canvas); - // FIXME: rebuilding the entire canvas each time is garbage m_canvas->destroy(); if (m_jack_driver) @@ -383,13 +387,6 @@ Patchage::menu_help_about() } -void -Patchage::close_about() -{ - m_about_window->hide(); -} - - /** Update the stored window location and size in the StateManager (in memory). */ void diff --git a/src/Patchage.h b/src/Patchage.h index f686e49..c7a3e0e 100644 --- a/src/Patchage.h +++ b/src/Patchage.h @@ -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. * @@ -57,16 +57,13 @@ public: inline void queue_refresh() { m_refresh = true; } protected: - void update_menu_items(); + void attach_menu_items(); - void menu_jack_launch(); - void menu_jack_connect(); - void menu_jack_disconnect(); - void menu_file_save(); + void menu_store_positions(); void menu_file_quit(); void menu_view_refresh(); void menu_help_about(); - void close_about(); + void zoom(double z); void zoom_changed(); bool idle_callback(); @@ -98,19 +95,20 @@ protected: bool m_refresh; Gtk::Window* m_main_window; - Gtk::Window* m_about_window; - Gtk::Label* m_about_project_label; + Gtk::AboutDialog* m_about_window; Gtk::MenuItem* m_menu_jack_launch; Gtk::MenuItem* m_menu_jack_connect; Gtk::MenuItem* m_menu_jack_disconnect; - Gtk::MenuItem* m_menu_file_save; + Gtk::MenuItem* m_menu_store_positions; Gtk::MenuItem* m_menu_file_quit; Gtk::MenuItem* m_menu_view_refresh; Gtk::MenuItem* m_menu_help_about; Gtk::ScrolledWindow* m_canvas_scrolledwindow; Gtk::HScale* m_zoom_slider; - Gtk::Button* m_about_close_button; - Gtk::Label* m_status_label; + Gtk::TextView* m_status_text; + Gtk::Paned* m_main_paned; + Gtk::Button* m_zoom_normal_button; + Gtk::Button* m_zoom_full_button; }; #endif // PATCHAGE_H diff --git a/src/PatchageFlowCanvas.cpp b/src/PatchageFlowCanvas.cpp index 2b9b19d..7485b6e 100644 --- a/src/PatchageFlowCanvas.cpp +++ b/src/PatchageFlowCanvas.cpp @@ -29,73 +29,72 @@ PatchageFlowCanvas::PatchageFlowCanvas(Patchage* app, int width, int height) } -PatchageModule* +boost::shared_ptr PatchageFlowCanvas::find_module(const string& name, ModuleType type) { - PatchageModule* pm = NULL; - for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) { - pm = (PatchageModule*)(*m).second; - if (pm->name() == name && pm->type() == type) { + boost::shared_ptr pm = boost::dynamic_pointer_cast((*m).second); + if (pm && pm->name() == name && pm->type() == type) { return pm; } } - return NULL; + return boost::shared_ptr(); } -PatchagePort* -PatchageFlowCanvas::find_port(const snd_seq_addr_t* alsa_addr, bool is_input) +boost::shared_ptr +PatchageFlowCanvas::find_port(const snd_seq_addr_t* alsa_addr) { - PatchagePort* pp = NULL; + boost::shared_ptr pp; for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) { - for (PortList::iterator p = (*m).second->ports().begin(); p != (*m).second->ports().end(); ++p) { - pp = (PatchagePort*)(*p); - if (pp->type() == ALSA_MIDI && pp->alsa_addr() + for (PortVector::const_iterator p = (*m).second->ports().begin(); p != (*m).second->ports().end(); ++p) { + pp = boost::dynamic_pointer_cast(*p); + if (pp && pp->type() == ALSA_MIDI && pp->alsa_addr() && pp->alsa_addr()->client == alsa_addr->client && pp->alsa_addr()->port == alsa_addr->port) - if (is_input == pp->is_input()) return pp; } } - return NULL; + return boost::shared_ptr(); } void -PatchageFlowCanvas::connect(const Port* port1, const Port* port2) +PatchageFlowCanvas::connect(boost::shared_ptr port1, boost::shared_ptr port2) { - PatchagePort* p1 = (PatchagePort*)port1; - PatchagePort* p2 = (PatchagePort*)port2; - + boost::shared_ptr p1 = boost::dynamic_pointer_cast(port1); + boost::shared_ptr p2 = boost::dynamic_pointer_cast(port2); + if (!p1 || !p2) + return; + if (p1->type() == JACK_AUDIO && p2->type() == JACK_AUDIO || (p1->type() == JACK_MIDI && p2->type() == JACK_MIDI)) - /*m_app->jack_driver()->connect(p1->module()->name(), p1->name(), - p2->module()->name(), p2->name());*/ m_app->jack_driver()->connect(p1, p2); else if (p1->type() == ALSA_MIDI && p2->type() == ALSA_MIDI) m_app->alsa_driver()->connect(p1, p2); else - m_app->status_message("Cannot make connection, incompatible port types."); + status_message("WARNING: Cannot make connection, incompatible port types."); } void -PatchageFlowCanvas::disconnect(const Port* port1, const Port* port2) +PatchageFlowCanvas::disconnect(boost::shared_ptr port1, boost::shared_ptr port2) { - PatchagePort* input = NULL; - PatchagePort* output = NULL; + boost::shared_ptr input; + boost::shared_ptr output; if (port1->is_input() && !port2->is_input()) { - input = (PatchagePort*)port1; - output = (PatchagePort*)port2; + input = boost::dynamic_pointer_cast(port1); + output = boost::dynamic_pointer_cast(port2); } else if (port2->is_input() && !port1->is_input()) { - input = (PatchagePort*)port2; - output = (PatchagePort*)port1; - } else { - m_app->status_message("Attempt to disconnect two input (or output) ports?? Please report bug."); + input = boost::dynamic_pointer_cast(port2); + output = boost::dynamic_pointer_cast(port1); + } + + if (!input || !output) { + status_message("ERROR: Attempt to disconnect mismatched/unknown ports"); return; } @@ -105,13 +104,13 @@ PatchageFlowCanvas::disconnect(const Port* port1, const Port* port2) else if (input->type() == ALSA_MIDI && output->type() == ALSA_MIDI) m_app->alsa_driver()->disconnect(output, input); else - m_app->status_message("Attempt to disconnect Jack audio port from Alsa Midi port?? Please report bug."); + status_message("ERROR: Attempt to disconnect ports with mismatched types"); } void PatchageFlowCanvas::status_message(const string& msg) { - m_app->status_message(msg); + m_app->status_message(string("[Canvas] ").append(msg)); } diff --git a/src/PatchageFlowCanvas.h b/src/PatchageFlowCanvas.h index 2636920..a99d658 100644 --- a/src/PatchageFlowCanvas.h +++ b/src/PatchageFlowCanvas.h @@ -33,11 +33,11 @@ class PatchageFlowCanvas : public FlowCanvas public: PatchageFlowCanvas(Patchage* m_app, int width, int height); - PatchageModule* find_module(const string& name, ModuleType type); - PatchagePort* find_port(const snd_seq_addr_t* alsa_addr, bool is_input); + boost::shared_ptr find_module(const string& name, ModuleType type); + boost::shared_ptr find_port(const snd_seq_addr_t* alsa_addr); - void connect(const Port* port1, const Port* port2); - void disconnect(const Port* port1, const Port* port2); + void connect(boost::shared_ptr port1, boost::shared_ptr port2); + void disconnect(boost::shared_ptr port1, boost::shared_ptr port2); void status_message(const string& msg); diff --git a/src/PatchageModule.h b/src/PatchageModule.h index 4400a68..58fa096 100644 --- a/src/PatchageModule.h +++ b/src/PatchageModule.h @@ -35,7 +35,7 @@ class PatchageModule : public Module { public: PatchageModule(Patchage* app, const string& title, ModuleType type, double x=0, double y=0) - : Module(app->canvas(), title, x, y), + : Module(*app->canvas(), title, x, y), m_app(app), m_type(type) { @@ -53,7 +53,7 @@ public: virtual ~PatchageModule() { } - virtual void add_patchage_port(const string& port_name, bool is_input, PortType type) + /*virtual void add_patchage_port(const string& port_name, bool is_input, PortType type) { new PatchagePort(this, type, port_name, is_input, m_app->state_manager()->get_port_color(type)); @@ -68,7 +68,7 @@ public: port->alsa_addr(addr); resize(); - } + }*/ virtual void load_location() { @@ -79,8 +79,8 @@ public: if (loc.x != -1) move_to(loc.x, loc.y); else - move_to((m_canvas->width()/2) - 100 + rand() % 400, - (m_canvas->height()/2) - 100 + rand() % 400); + move_to((m_canvas.width()/2) - 100 + rand() % 400, + (m_canvas.height()/2) - 100 + rand() % 400); } void split() { @@ -103,7 +103,7 @@ public: virtual void show_dialog() {} virtual void on_right_click(GdkEventButton* ev) { m_menu.popup(ev->button, ev->time); } virtual void menu_disconnect_all() { - for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p) + for (PortVector::iterator p = m_ports.begin(); p != m_ports.end(); ++p) (*p)->disconnect_all(); } diff --git a/src/PatchagePort.h b/src/PatchagePort.h index 601bce9..7ebc995 100644 --- a/src/PatchagePort.h +++ b/src/PatchagePort.h @@ -1,11 +1,11 @@ -/* This file is part of Om. Copyright (C) 2004 Dave Robillard. +/* This file is part of Patchage. Copyright (C) 2004 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. * @@ -14,7 +14,6 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #ifndef PATCHAGEPORT_H #define PATCHAGEPORT_H @@ -37,7 +36,7 @@ enum PortType { JACK_AUDIO, JACK_MIDI, ALSA_MIDI }; class PatchagePort : public LibFlowCanvas::Port { public: - PatchagePort(LibFlowCanvas::Module* module, PortType type, const string& name, bool is_input, int color) + PatchagePort(boost::shared_ptr module, PortType type, const string& name, bool is_input, int color) : Port(module, name, is_input, color), m_type(type) { @@ -53,7 +52,7 @@ public: { return (m_type == ALSA_MIDI) ? &m_alsa_addr : NULL; } /** Returns the full name of this port, as "modulename:portname" */ - string full_name() const { return m_module->name() + ":" + m_name; } + string full_name() const { return m_module.lock()->name() + ":" + m_name; } PortType type() const { return m_type; } diff --git a/src/StateManager.cpp b/src/StateManager.cpp index 50429e1..f4bab3a 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.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. * diff --git a/src/StateManager.h b/src/StateManager.h index b584308..06843bd 100644 --- a/src/StateManager.h +++ b/src/StateManager.h @@ -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. * diff --git a/src/main.cpp b/src/main.cpp index 5646b1c..a2da0ef 100644 --- a/src/main.cpp +++ b/src/main.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. * @@ -29,6 +29,12 @@ int main(int argc, char** argv) { try { + + //lash_args_t* const lash_args = lash_extract_args(&argc, &argv); + + //lash_client_t* const lash_server_client = lash_init(lash_args, "Patchage Server Interface", + // LASH_Server_Interface, LASH_PROTOCOL(2, 0)); + Gnome::Canvas::init(); Gtk::Main app(argc, argv); diff --git a/src/patchage.glade b/src/patchage.glade index 322a714..9bed33c 100644 --- a/src/patchage.glade +++ b/src/patchage.glade @@ -44,17 +44,17 @@ - + True - Launch Jack + _Open Session True - - + + - + True - gtk-execute + gtk-open 1 0.5 0.5 @@ -66,17 +66,17 @@ - + True - Connect to _Jack + _Save Session True - - + + - + True - gtk-connect + gtk-save 1 0.5 0.5 @@ -88,17 +88,17 @@ - + True - Disconnect from Jack + Save Session _As True - - + + - + True - gtk-disconnect + gtk-save-as 1 0.5 0.5 @@ -110,7 +110,7 @@ - + True @@ -118,13 +118,13 @@ True - Launch Lash + Launch LASH True - + - + True gtk-execute 1 @@ -140,13 +140,13 @@ True - Connect to _Lash + Connect to _LASH True - + True gtk-connect 1 @@ -162,13 +162,85 @@ True - Disconnect from Lash + Disconnect from LASH True - + + True + gtk-disconnect + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Launch JACK + True + + + + + + True + gtk-execute + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Connect to _JACK + True + + + + + + True + gtk-connect + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Disconnect from JACK + True + + + + + True gtk-disconnect 1 @@ -190,13 +262,13 @@ True - Connect to _Alsa + Connect to _ALSA True - + True gtk-connect 1 @@ -212,13 +284,13 @@ True - Disconnect from Alsa + Disconnect from ALSA True - + True gtk-disconnect 1 @@ -238,7 +310,7 @@ - + True _Store Positions True @@ -246,7 +318,7 @@ - + True gtk-save 1 @@ -290,9 +362,22 @@ True - gtk-refresh - True - + _Refresh + True + + + + + + True + gtk-refresh + 1 + 0.5 + 0.5 + 0 + 0 + + @@ -330,272 +415,192 @@ - + True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_ICONS + True + True - - - - - 0 - True - True - - + + True + True + True + False - - - True - False - 0 + + + True + True + GTK_RELIEF_NORMAL + True - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 + + + True + gtk-zoom-100 + 4 + 0.5 + 0.5 + 0 + 0 + + + + - 2 - True - True + False + False - + True - True - False + True True + False + + + + True + True + GTK_RELIEF_NORMAL + True + + + + True + gtk-zoom-fit + 4 + 0.5 + 0.5 + 0 + 0 + + + + - 0 False - False + False - + True - False - 0 - - - - True - Zoom: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - + True + True + False 150 True True - True + False GTK_POS_RIGHT 1 GTK_UPDATE_CONTINUOUS False - 1 0.1 2 0 0 0 + 1 0.10000000149 2 0 0 0 - - 5 - True - True - - 0 - False - False + True + False - - 2 - False - False - - - - - - - - 320 - 200 - About Patchage - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - False - False - True - True - True - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - <span size="xx-large" weight="bold">Patchage</span> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - - True - A modular patch bay for: - -Jack Audio Connection Kit -ALSA Sequencer - False - False - GTK_JUSTIFY_CENTER - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - Copyright © 2005 Dave Robillard - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 10 - False - False - - - - - - True - GTK_BUTTONBOX_DEFAULT_STYLE - 0 - 0 False - False + True - + True - GTK_BUTTONBOX_DEFAULT_STYLE + False 0 - - 66 - 26 + + 407 True True - gtk-close - True - GTK_RELIEF_NORMAL - True + 1 + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + False + True + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + False + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + False + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + True + True + + + + 2 + True + True + - 0 + 2 True True @@ -604,4 +609,29 @@ ALSA Sequencer + + True + Patchage + © 2006 Dave Robillard + A control centre for audio and music production systems + 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. + +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 more details. + +You should have received a copy of the GNU General Public License +along with Patchage; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + False + http://codeson.net/software/patchage + Dave Robillard <dave@codeson.net> + translator-credits + + -- cgit v1.2.1