diff options
Diffstat (limited to 'src/JackDriver.cpp')
-rw-r--r-- | src/JackDriver.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp new file mode 100644 index 0000000..5bb084e --- /dev/null +++ b/src/JackDriver.cpp @@ -0,0 +1,258 @@ +/* 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 + * 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 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cassert> +#include <cstring> +#include <string> +#include <iostream> +#include <jack/jack.h> +#include "PatchageFlowCanvas.h" +#include "JackDriver.h" +#include "Patchage.h" +#include "PatchageModule.h" + +using std::cerr; using std::endl; using std::cout; +using std::string; + +using namespace LibFlowCanvas; + + +JackDriver::JackDriver(Patchage* app) +: m_app(app), + m_canvas(app->canvas()), + m_client(NULL) +{ +} + + +JackDriver::~JackDriver() +{ + detach(); +} + + +/** Connect to Jack. + */ +void +JackDriver::attach(bool launch_daemon) +{ + cout << "Connecting to Jack... "; + cout.flush(); + + if (m_client != NULL) { + cout << "already connected. " << endl; + return; + } + + jack_options_t options = (!launch_daemon) ? JackNoStartServer : JackNullOption; + m_client = jack_client_open("Patchage", options, NULL); + if (m_client == NULL) { + cout << "Failed" << endl; + } else { + 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; + } +} + + +void +JackDriver::detach() +{ + if (m_client != NULL) { + jack_deactivate(m_client); + jack_client_close(m_client); + m_client = NULL; + cout << "Disconnected from Jack" << endl; + } +} + + +/** Refresh all Jack audio ports/connections. + * To be called from GTK thread only. + */ +void +JackDriver::refresh() +{ + if (m_client == NULL) + 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) + for (int i=0; ports[i]; ++i) { + port = jack_port_by_name(m_client, ports[i]); + client1_name = ports[i]; + client1_name = client1_name.substr(0, client1_name.find(":")); + + ModuleType type = InputOutput; + //if (m_app->state_manager()->get_module_split(client1_name) + // || jack_port_flags(port) & JackPortIsTerminal) { + if (m_app->state_manager()->get_module_split(client1_name, + (jack_port_flags(port) & JackPortIsTerminal))) { + if (jack_port_flags(port) & JackPortIsInput) { + type = Input; + } else { + type = Output; + } + } + + m = (PatchageModule*)m_canvas->find_module(client1_name, type); + + if (m == NULL) { + m = new PatchageModule(m_app, client1_name, type); + m->load_location(); + m->store_location(); + m_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, "8 bit raw midi")) + port_type = JACK_MIDI; + + m->add_patchage_port(jack_port_short_name(port), + (jack_port_flags(port) & JackPortIsInput), + port_type); + } + + // 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) + 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(':')); + + m_canvas->add_connection(client1_name, port1_name, client2_name, port2_name); + } + free(connected_ports); + } + free(ports); + } + + undirty(); +} + + +/** Connects two Jack audio ports. + * To be called from GTK thread only. + * \return Whether connection succeeded. + */ +bool +JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* const 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); + + return (!result); +} + + +/** Disconnects two Jack audio ports. + * To be called from GTK thread only. + * \return Whether disconnection succeeded. + */ +bool +JackDriver::disconnect(const PatchagePort* const src_port, const 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); + + return (!result); +} + + +void +JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int registered, void* me) +{ + assert(me != NULL); + assert(((JackDriver*)me)->m_client != NULL); + ((JackDriver*)me)->m_is_dirty = true; +} + + +int +JackDriver::jack_graph_order_cb(void* me) +{ + assert(me != NULL); + assert(((JackDriver*)me)->m_client != NULL); + ((JackDriver*)me)->m_is_dirty = true; + + return 0; +} + + +void +JackDriver::jack_shutdown_cb(void* me) +{ + assert(me != NULL); + ((JackDriver*)me)->m_client = NULL; + ((JackDriver*)me)->m_is_dirty = true; +} + + |