summaryrefslogtreecommitdiffstats
path: root/src/JackDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/JackDriver.cpp')
-rw-r--r--src/JackDriver.cpp258
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;
+}
+
+