From 43d51948ccae71b8f0a1c1710e25cf36da8d7d7c Mon Sep 17 00:00:00 2001
From: David Robillard
Date: Fri, 8 Sep 2006 06:23:25 +0000
Subject: Renamed communications classes for consistency. Removed engine
dependency on OSC (mostly).
git-svn-id: http://svn.drobilla.net/lad/ingen@120 a436a847-0d15-0410-975c-d299462d15a1
---
src/libs/client/Makefile.am | 8 +-
src/libs/client/ModelEngineInterface.h | 1 -
src/libs/client/OSCClientReceiver.cpp | 415 +++++++++++++
src/libs/client/OSCClientReceiver.h | 120 ++++
src/libs/client/OSCEngineInterface.cpp | 348 -----------
src/libs/client/OSCEngineInterface.h | 145 -----
src/libs/client/OSCEngineSender.cpp | 348 +++++++++++
src/libs/client/OSCEngineSender.h | 145 +++++
src/libs/client/OSCListener.cpp | 415 -------------
src/libs/client/OSCListener.h | 121 ----
src/libs/client/OSCModelEngineInterface.cpp | 4 +-
src/libs/client/OSCModelEngineInterface.h | 13 +-
src/libs/client/Store.cpp | 2 +-
src/libs/engine/ClientBroadcaster.cpp | 12 +-
src/libs/engine/Engine.cpp | 10 +-
src/libs/engine/Engine.h | 9 +-
src/libs/engine/EventSource.h | 7 +-
src/libs/engine/JackAudioDriver.cpp | 50 +-
src/libs/engine/JackAudioDriver.h | 2 -
src/libs/engine/Makefile.am | 8 +-
src/libs/engine/OSCClient.cpp | 500 ---------------
src/libs/engine/OSCClient.h | 131 ----
src/libs/engine/OSCClientSender.cpp | 487 +++++++++++++++
src/libs/engine/OSCClientSender.h | 131 ++++
src/libs/engine/OSCEngineReceiver.cpp | 909 ++++++++++++++++++++++++++++
src/libs/engine/OSCEngineReceiver.h | 129 ++++
src/libs/engine/OSCReceiver.cpp | 909 ----------------------------
src/libs/engine/OSCReceiver.h | 129 ----
src/libs/engine/QueuedEventSource.cpp | 36 +-
src/libs/engine/QueuedEventSource.h | 9 +-
30 files changed, 2761 insertions(+), 2792 deletions(-)
create mode 100644 src/libs/client/OSCClientReceiver.cpp
create mode 100644 src/libs/client/OSCClientReceiver.h
delete mode 100644 src/libs/client/OSCEngineInterface.cpp
delete mode 100644 src/libs/client/OSCEngineInterface.h
create mode 100644 src/libs/client/OSCEngineSender.cpp
create mode 100644 src/libs/client/OSCEngineSender.h
delete mode 100644 src/libs/client/OSCListener.cpp
delete mode 100644 src/libs/client/OSCListener.h
delete mode 100644 src/libs/engine/OSCClient.cpp
delete mode 100644 src/libs/engine/OSCClient.h
create mode 100644 src/libs/engine/OSCClientSender.cpp
create mode 100644 src/libs/engine/OSCClientSender.h
create mode 100644 src/libs/engine/OSCEngineReceiver.cpp
create mode 100644 src/libs/engine/OSCEngineReceiver.h
delete mode 100644 src/libs/engine/OSCReceiver.cpp
delete mode 100644 src/libs/engine/OSCReceiver.h
(limited to 'src/libs')
diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am
index 01cff357..f8a9a1cf 100644
--- a/src/libs/client/Makefile.am
+++ b/src/libs/client/Makefile.am
@@ -7,12 +7,12 @@ libomclient_la_CXXFLAGS = -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir
libomclient_la_SOURCES = \
ClientInterface.h \
- OSCEngineInterface.h \
- OSCEngineInterface.cpp \
+ OSCEngineSender.h \
+ OSCEngineSender.cpp \
OSCModelEngineInterface.h \
OSCModelEngineInterface.cpp \
- OSCListener.h \
- OSCListener.cpp \
+ OSCClientReceiver.h \
+ OSCClientReceiver.cpp \
SigClientInterface.h \
DirectSigClientInterface.h \
ThreadedSigClientInterface.h \
diff --git a/src/libs/client/ModelEngineInterface.h b/src/libs/client/ModelEngineInterface.h
index 763cdc69..2bc5db14 100644
--- a/src/libs/client/ModelEngineInterface.h
+++ b/src/libs/client/ModelEngineInterface.h
@@ -31,7 +31,6 @@ namespace Client {
class NodeModel;
class PresetModel;
class PatchModel;
-class OSCListener;
class ModelClientInterface;
diff --git a/src/libs/client/OSCClientReceiver.cpp b/src/libs/client/OSCClientReceiver.cpp
new file mode 100644
index 00000000..56d8ea14
--- /dev/null
+++ b/src/libs/client/OSCClientReceiver.cpp
@@ -0,0 +1,415 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OSCClientReceiver.h"
+//#include "NodeModel.h"
+//#include "PluginModel.h"
+#include
+#include
+#include
+#include
+using std::cerr; using std::cout; using std::endl;
+
+namespace Ingen {
+namespace Client {
+
+
+/** Construct a OSCClientReceiver with a user-provided ModelClientInterface object for notification
+ * of engine events.
+ */
+OSCClientReceiver::OSCClientReceiver(int listen_port)
+: _listen_port(listen_port),
+ _st(NULL)//,
+// _receiving_node(false),
+// _receiving_node_model(NULL),
+// _receiving_node_num_ports(0),
+// _num_received_ports(0)
+{
+ start();
+}
+
+
+OSCClientReceiver::~OSCClientReceiver()
+{
+ stop();
+}
+
+
+void
+OSCClientReceiver::start()
+{
+ if (_st != NULL)
+ return;
+
+ if (_listen_port == 0) {
+ _st = lo_server_thread_new(NULL, error_cb);
+ _listen_port = lo_server_thread_get_port(_st);
+ } else {
+ char port_str[8];
+ snprintf(port_str, 8, "%d", _listen_port);
+ _st = lo_server_thread_new(port_str, error_cb);
+ }
+
+ if (_st == NULL) {
+ cerr << "[OSCClientReceiver] Could not start OSC listener. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ } else {
+ cout << "[OSCClientReceiver] Started OSC listener on port " << lo_server_thread_get_port(_st) << endl;
+ }
+
+ // FIXME
+ lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL);
+
+ //lo_server_thread_add_method(_st, "/om/response/ok", "i", om_response_ok_cb, this);
+ //lo_server_thread_add_method(_st, "/om/response/error", "is", om_responseerror_cb, this);
+
+ setup_callbacks();
+
+ // Display any uncaught messages to the console
+ //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL);
+
+ lo_server_thread_start(_st);
+}
+
+
+void
+OSCClientReceiver::stop()
+{
+ if (_st != NULL) {
+ //unregister_client();
+ lo_server_thread_free(_st);
+ _st = NULL;
+ }
+}
+
+
+int
+OSCClientReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data)
+{
+ printf("[OSCMsg] %s (%s)\t", path, types);
+
+ for (int i=0; i < argc; ++i) {
+ lo_arg_pp(lo_type(types[i]), argv[i]);
+ printf("\t");
+ }
+ printf("\n");
+
+ /*for (int i=0; i < argc; ++i) {
+ printf(" '%c' ", types[i]);
+ lo_arg_pp(lo_type(types[i]), argv[i]);
+ printf("\n");
+ }
+ printf("\n");*/
+
+ return 1; // not handled
+}
+
+
+void
+OSCClientReceiver::error_cb(int num, const char* msg, const char* path)
+{
+ cerr << "Got error from server: " << msg << endl;
+}
+
+
+
+int
+OSCClientReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data)
+{
+ string msg = "Received unknown OSC message: ";
+ msg += path;
+
+ cerr << msg << endl;
+
+ return 0;
+}
+
+
+void
+OSCClientReceiver::setup_callbacks()
+{
+ lo_server_thread_add_method(_st, "/om/num_plugins", "i", num_plugins_cb, this);
+ lo_server_thread_add_method(_st, "/om/plugin", "sss", plugin_cb, this);
+ lo_server_thread_add_method(_st, "/om/new_patch", "si", new_patch_cb, this);
+ lo_server_thread_add_method(_st, "/om/destroyed", "s", destroyed_cb, this);
+ lo_server_thread_add_method(_st, "/om/patch_enabled", "s", patch_enabled_cb, this);
+ lo_server_thread_add_method(_st, "/om/patch_disabled", "s", patch_disabled_cb, this);
+ lo_server_thread_add_method(_st, "/om/patch_cleared", "s", patch_cleared_cb, this);
+ lo_server_thread_add_method(_st, "/om/object_renamed", "ss", object_renamed_cb, this);
+ lo_server_thread_add_method(_st, "/om/new_connection", "ss", connection_cb, this);
+ lo_server_thread_add_method(_st, "/om/disconnection", "ss", disconnection_cb, this);
+ lo_server_thread_add_method(_st, "/om/new_node", "sssii", new_node_cb, this);
+ lo_server_thread_add_method(_st, "/om/new_port", "ssi", new_port_cb, this);
+ lo_server_thread_add_method(_st, "/om/metadata/update", "sss", metadata_update_cb, this);
+ lo_server_thread_add_method(_st, "/om/control_change", "sf", control_change_cb, this);
+ lo_server_thread_add_method(_st, "/om/program_add", "siis", program_add_cb, this);
+ lo_server_thread_add_method(_st, "/om/program_remove", "sii", program_remove_cb, this);
+}
+
+
+/** Catches errors that aren't a direct result of a client request.
+ */
+int
+OSCClientReceiver::m_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ cerr << "ERROR: " << argv[0]->s << endl;
+ // FIXME
+ //error((char*)argv[0]);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_new_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ new_patch(&argv[0]->s, argv[1]->i); // path, poly
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_destroyed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ object_destroyed((const char*)&argv[0]->s);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_patch_enabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ patch_enabled((const char*)&argv[0]->s);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_patch_disabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ patch_disabled((const char*)&argv[0]->s);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_patch_cleared_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ patch_cleared((const char*)&argv[0]->s);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_object_renamed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ object_renamed((const char*)&argv[0]->s, (const char*)&argv[1]->s);
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* const src_port_path = &argv[0]->s;
+ const char* const dst_port_path = &argv[1]->s;
+
+ connection(src_port_path, dst_port_path);
+
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* src_port_path = &argv[0]->s;
+ const char* dst_port_path = &argv[1]->s;
+
+ disconnection(src_port_path, dst_port_path);
+
+ return 0;
+}
+
+
+/** Notification of a new node creation.
+ */
+int
+OSCClientReceiver::m_new_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* type = &argv[0]->s;
+ const char* uri = &argv[1]->s;
+ const char* node_path = &argv[2]->s;
+ const int32_t poly = argv[3]->i;
+ const int32_t num_ports = argv[4]->i;
+
+ new_node(type, uri, node_path, poly, num_ports);
+
+ /*_receiving_node_model = new NodeModel(node_path);
+ _receiving_node_model->polyphonic((poly == 1));
+ _receiving_node_num_ports = num_ports;
+
+ PluginModel* pi = new PluginModel(type, uri);
+ _receiving_node_model->plugin(pi);
+
+ _receiving_node = true;
+ _num_received_ports = 0;
+ */
+ return 0;
+}
+
+
+/** Notification of a new port creation.
+ */
+int
+OSCClientReceiver::m_new_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[0]->s;
+ const char* type = &argv[1]->s;
+ bool is_output = (argv[2]->i == 1);
+ /*const char* direction = &argv[2]->s;
+ const char* hint = &argv[3]->s;
+ float default_val = argv[4]->f;
+ float min_val = argv[5]->f;
+ float max_val = argv[6]->f;*/
+
+ new_port(port_path, type, is_output);
+#if 0
+ PortModel::Type ptype = PortModel::CONTROL;
+ if (!strcmp(type, "AUDIO")) ptype = PortModel::AUDIO;
+ else if (!strcmp(type, "CONTROL")) ptype = PortModel::CONTROL;
+ else if (!strcmp(type, "MIDI")) ptype = PortModel::MIDI;
+ else cerr << "[OSCClientReceiver] WARNING: Unknown port type received (" << type << ")" << endl;
+
+#if 0
+ PortModel::Direction pdir = PortModel::INPUT;
+ if (!strcmp(direction, "INPUT")) pdir = PortModel::INPUT;
+ else if (!strcmp(direction, "OUTPUT")) pdir = PortModel::OUTPUT;
+ else cerr << "[OSCClientReceiver] WARNING: Unknown port direction received (" << direction << ")" << endl;
+#endif
+ PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT;
+
+/*
+ PortModel::Hint phint = PortModel::NONE;
+ if (!strcmp(hint, "LOGARITHMIC")) phint = PortModel::LOGARITHMIC;
+ else if (!strcmp(hint, "INTEGER")) phint = PortModel::INTEGER;
+ else if (!strcmp(hint, "TOGGLE")) phint = PortModel::TOGGLE;
+
+ PortModel* port_model = new PortModel(port_path, ptype, pdir, phint, default_val, min_val, max_val);
+*/
+ PortModel* port_model = new PortModel(port_path, ptype, pdir);
+ if (m_receiving_node) {
+ assert(m_receiving_node_model);
+ m_receiving_node_model->add_port(port_model);
+ ++m_num_received_ports;
+
+ // If transmission is done, send new node to client
+ if (m_num_received_ports == m_receiving_node_num_ports) {
+ new_node_model(m_receiving_node_model);
+ m_receiving_node = false;
+ m_receiving_node_model = NULL;
+ m_num_received_ports = 0;
+ }
+ } else {
+ new_port_model(port_model);
+ }
+
+#endif
+ return 0;
+}
+
+
+/** Notification of a new or updated piece of metadata.
+ */
+int
+OSCClientReceiver::m_metadata_update_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* obj_path = &argv[0]->s;
+ const char* key = &argv[1]->s;
+ const char* value = &argv[2]->s;
+
+ metadata_update(obj_path, key, value);
+
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_control_change_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* const port_path = &argv[0]->s;
+ const float value = argv[1]->f;
+
+ control_change(port_path, value);
+
+ return 0;
+}
+
+
+/** Number of plugins in engine, should precede /om/plugin messages in response
+ * to a /om/send_plugins
+ */
+int
+OSCClientReceiver::m_num_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ /** Not worth it implementing a ModelClientInterface callback for this (?)
+ * Or I'm just lazy. FIXME? */
+ num_plugins(argv[0]->i);
+
+ return 0;
+}
+
+
+/** A plugin info response from the server, in response to a /send_plugins
+ */
+int
+OSCClientReceiver::m_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ assert(argc == 3 && !strcmp(types, "sss"));
+ new_plugin(&argv[0]->s, &argv[1]->s, &argv[2]->s); // type, uri
+
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_program_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[0]->s;
+ int32_t bank = argv[1]->i;
+ int32_t program = argv[2]->i;
+ const char* name = &argv[3]->s;
+
+ program_add(node_path, bank, program, name);
+
+ return 0;
+}
+
+
+int
+OSCClientReceiver::m_program_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[0]->s;
+ int32_t bank = argv[1]->i;
+ int32_t program = argv[2]->i;
+
+ program_remove(node_path, bank, program);
+
+ return 0;
+}
+
+
+} // namespace Client
+} // namespace Ingen
diff --git a/src/libs/client/OSCClientReceiver.h b/src/libs/client/OSCClientReceiver.h
new file mode 100644
index 00000000..60fa9495
--- /dev/null
+++ b/src/libs/client/OSCClientReceiver.h
@@ -0,0 +1,120 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OSCCLIENTRECEIVER_H
+#define OSCCLIENTRECEIVER_H
+
+#include
+#include
+#include "interface/ClientInterface.h"
+
+namespace Ingen {
+
+/** Client library */
+namespace Client {
+
+//class NodeModel;
+//class PresetModel;
+
+/* Some boilerplate killing macros... */
+#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg
+
+/* Defines a static handler to be passed to lo_add_method, which is a trivial
+ * wrapper around a non-static method that does the real work. Makes a whoole
+ * lot of ugly boiler plate go away */
+#define LO_HANDLER(name) \
+int m_##name##_cb (LO_HANDLER_ARGS);\
+inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\
+{ return ((OSCClientReceiver*)osc_listener)->m_##name##_cb(path, types, argv, argc, msg); }
+
+
+/** Callbacks for "notification band" OSC messages.
+ *
+ * Receives all notification of engine state, but not replies on the "control
+ * band". See OSC namespace documentation for details.
+ *
+ * Right now this class and Comm share the same lo_server_thread and the barrier
+ * between them is a bit odd, but eventually this class will be able to listen
+ * on a completely different port (ie have it's own lo_server_thread) to allow
+ * things like listening to the notification band over TCP while sending commands
+ * on the control band over UDP.
+ *
+ * \ingroup IngenClient
+ */
+class OSCClientReceiver : virtual public Ingen::Shared::ClientInterface
+{
+public:
+ OSCClientReceiver(int listen_port);
+ ~OSCClientReceiver();
+
+ void start();
+ void stop();
+
+ int listen_port() { return _listen_port; }
+ string listen_url() { return lo_server_thread_get_url(_st); }
+
+private:
+ // Prevent copies
+ OSCClientReceiver(const OSCClientReceiver& copy);
+ OSCClientReceiver& operator=(const OSCClientReceiver& copy);
+
+ void setup_callbacks();
+
+ static void error_cb(int num, const char* msg, const char* path);
+ static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data);
+ static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver);
+ /*
+ inline static int om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm);
+ int m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data);
+ inline static int om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm);
+ int m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data);
+*/
+ int _listen_port;
+ lo_server_thread _st;
+
+ // Used for receiving nodes - multiple messages are received before
+ // sending an event to the client (via ModelClientInterface)
+ //bool _receiving_node;
+ //NodeModel* _receiving_node_model;
+ //int32_t _receiving_node_num_ports;
+ //int32_t _num_received_ports;
+
+ LO_HANDLER(error);
+ LO_HANDLER(num_plugins);
+ LO_HANDLER(plugin);
+ LO_HANDLER(plugin_list_end);
+ LO_HANDLER(new_patch);
+ LO_HANDLER(destroyed);
+ LO_HANDLER(patch_enabled);
+ LO_HANDLER(patch_disabled);
+ LO_HANDLER(patch_cleared);
+ LO_HANDLER(object_renamed);
+ LO_HANDLER(connection);
+ LO_HANDLER(disconnection);
+ LO_HANDLER(new_node);
+ LO_HANDLER(new_port);
+ LO_HANDLER(metadata_update);
+ LO_HANDLER(control_change);
+ LO_HANDLER(program_add);
+ LO_HANDLER(program_remove);
+};
+
+
+} // namespace Client
+
+} // namespace Ingen
+
+#endif // OSCCLIENTRECEIVER_H
diff --git a/src/libs/client/OSCEngineInterface.cpp b/src/libs/client/OSCEngineInterface.cpp
deleted file mode 100644
index b747e2e4..00000000
--- a/src/libs/client/OSCEngineInterface.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "OSCEngineInterface.h"
-#include "interface/ClientKey.h"
-
-namespace Ingen {
-namespace Client {
-
-/** Note the sending port is implicitly set by liblo, lo_send by default sends
- * from the most recently created server, so create the OSC listener before
- * this to have it all happen on the same port. Yeah, this is a big magic :/
- */
-OSCEngineInterface::OSCEngineInterface(const string& engine_url)
-: _engine_url(engine_url)
-, _engine_addr(lo_address_new_from_url(engine_url.c_str()))
-, _id(0)
-{
-}
-
-
-OSCEngineInterface::~OSCEngineInterface()
-{
- lo_address_free(_engine_addr);
-}
-
-
-/* *** EngineInterface implementation below here *** */
-
-
-/** Register with the engine via OSC.
- *
- * Note that this does not actually use 'key', since the engine creates
- * it's own key for OSC clients (namely the incoming URL), for NAT
- * traversal. It is a parameter to remain compatible with EngineInterface.
- */
-void
-OSCEngineInterface::register_client(ClientKey key, CountedPtr client)
-{
- // FIXME: use parameters.. er, somehow.
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/register_client", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::unregister_client(ClientKey key)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/unregister_client", "i", next_id());
-}
-
-
-
-// Engine commands
-void
-OSCEngineInterface::load_plugins()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/load_plugins", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::activate()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/activate", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::deactivate()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/deactivate", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::quit()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/engine/quit", "i", next_id());
-}
-
-
-
-// Object commands
-
-void
-OSCEngineInterface::create_patch(const string& path,
- uint32_t poly)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/create_patch", "isi",
- next_id(),
- path.c_str(),
- poly);
-}
-
-
-void
-OSCEngineInterface::create_port(const string& path,
- const string& data_type,
- bool is_output)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/create_port", "issi",
- next_id(),
- path.c_str(),
- data_type.c_str(),
- (is_output ? 1 : 0));
-}
-
-
-void
-OSCEngineInterface::create_node(const string& path,
- const string& plugin_type,
- const string& plugin_uri,
- bool polyphonic)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/create_node", "isssi",
- next_id(),
- path.c_str(),
- plugin_type.c_str(),
- plugin_uri.c_str(),
- (polyphonic ? 1 : 0));
-}
-
-
-void
-OSCEngineInterface::rename(const string& old_path,
- const string& new_name)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/rename", "iss",
- next_id(),
- old_path.c_str(),
- new_name.c_str());
-}
-
-
-void
-OSCEngineInterface::destroy(const string& path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/destroy", "is",
- next_id(),
- path.c_str());
-}
-
-
-void
-OSCEngineInterface::clear_patch(const string& patch_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/clear_patch", "is",
- next_id(),
- patch_path.c_str());
-}
-
-
-void
-OSCEngineInterface::enable_patch(const string& patch_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/enable_patch", "is",
- next_id(),
- patch_path.c_str());
-}
-
-
-void
-OSCEngineInterface::disable_patch(const string& patch_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/disable_patch", "is",
- next_id(),
- patch_path.c_str());
-}
-
-
-void
-OSCEngineInterface::connect(const string& src_port_path,
- const string& dst_port_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/connect", "iss",
- next_id(),
- src_port_path.c_str(),
- dst_port_path.c_str());
-}
-
-
-void
-OSCEngineInterface::disconnect(const string& src_port_path,
- const string& dst_port_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/disconnect", "iss",
- next_id(),
- src_port_path.c_str(),
- dst_port_path.c_str());
-}
-
-
-void
-OSCEngineInterface::disconnect_all(const string& node_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/disconnect_all", "is",
- next_id(),
- node_path.c_str());
-}
-
-
-void
-OSCEngineInterface::set_port_value(const string& port_path,
- float val)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/set_port_value", "isf",
- next_id(),
- port_path.c_str(),
- val);
-}
-
-
-void
-OSCEngineInterface::set_port_value(const string& port_path,
- uint32_t voice,
- float val)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/set_port_value", "isif",
- next_id(),
- port_path.c_str(),
- voice,
- val);
-}
-
-
-void
-OSCEngineInterface::set_port_value_queued(const string& port_path,
- float val)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/set_port_value_queued", "isf",
- next_id(),
- port_path.c_str(),
- val);
-}
-
-
-void
-OSCEngineInterface::set_program(const string& node_path,
- uint32_t bank,
- uint32_t program)
-{
- assert(_engine_addr);
- lo_send(_engine_addr,
- (string("/dssi") + node_path + "/program").c_str(),
- "ii",
- bank,
- program);
-}
-
-
-void
-OSCEngineInterface::midi_learn(const string& node_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/synth/midi_learn", "is",
- next_id(),
- node_path.c_str());
-}
-
-
-void
-OSCEngineInterface::set_metadata(const string& obj_path,
- const string& predicate,
- const string& value)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/metadata/set", "isss",
- next_id(),
- obj_path.c_str(),
- predicate.c_str(),
- value.c_str());
-}
-
-
-// Requests //
-
-void
-OSCEngineInterface::ping()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/ping", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::request_port_value(const string& port_path)
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/request/port_value", "is",
- next_id(),
- port_path.c_str());
-}
-
-
-void
-OSCEngineInterface::request_plugins()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/request/plugins", "i", next_id());
-}
-
-
-void
-OSCEngineInterface::request_all_objects()
-{
- assert(_engine_addr);
- lo_send(_engine_addr, "/om/request/all_objects", "i", next_id());
-}
-
-
-
-} // namespace Client
-} // namespace Ingen
-
-
diff --git a/src/libs/client/OSCEngineInterface.h b/src/libs/client/OSCEngineInterface.h
deleted file mode 100644
index 4405438c..00000000
--- a/src/libs/client/OSCEngineInterface.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef OSCENGINEINTERFACE_H
-#define OSCENGINEINTERFACE_H
-
-#include
-#include
-#include
-#include "interface/EngineInterface.h"
-using std::string;
-using Ingen::Shared::EngineInterface;
-using Ingen::Shared::ClientInterface;
-using Ingen::Shared::ClientKey;
-
-
-namespace Ingen {
-namespace Client {
-
-/* OSC (via liblo) interface to the engine.
- *
- * Clients can use this opaquely as an EngineInterface* to control the engine
- * over OSC (whether over a network or not, etc).
- *
- * \ingroup IngenClient
- */
-class OSCEngineInterface : public EngineInterface
-{
-public:
- OSCEngineInterface(const string& engine_url);
-
- ~OSCEngineInterface();
-
- string engine_url() { return _engine_url; }
-
- inline size_t next_id()
- { if (_id != -1) { _id = (_id == -2) ? 0 : _id+1; } return _id; }
-
- void enable_responses() { _id = 0; }
- void disable_responses() { _id = -1; }
-
-
- /* *** EngineInterface implementation below here *** */
-
- // Client registration
- void register_client(ClientKey key, CountedPtr client);
- void unregister_client(ClientKey key);
-
-
- // Engine commands
- void load_plugins();
- void activate();
- void deactivate();
- void quit();
-
-
- // Object commands
-
- void create_patch(const string& path,
- uint32_t poly);
-
- void create_port(const string& path,
- const string& data_type,
- bool is_output);
-
- void create_node(const string& path,
- const string& plugin_type,
- const string& plugin_uri,
- bool polyphonic);
-
- void rename(const string& old_path,
- const string& new_name);
-
- void destroy(const string& path);
-
- void clear_patch(const string& patch_path);
-
- void enable_patch(const string& patch_path);
-
- void disable_patch(const string& patch_path);
-
- void connect(const string& src_port_path,
- const string& dst_port_path);
-
- void disconnect(const string& src_port_path,
- const string& dst_port_path);
-
- void disconnect_all(const string& node_path);
-
- void set_port_value(const string& port_path,
- float val);
-
- void set_port_value(const string& port_path,
- uint32_t voice,
- float val);
-
- void set_port_value_queued(const string& port_path,
- float val);
-
- void set_program(const string& node_path,
- uint32_t bank,
- uint32_t program);
-
- void midi_learn(const string& node_path);
-
- void set_metadata(const string& obj_path,
- const string& predicate,
- const string& value);
-
- // Requests //
-
- void ping();
-
- void request_port_value(const string& port_path);
-
- void request_plugins();
-
- void request_all_objects();
-
-protected:
- string _engine_url;
- lo_address _engine_addr;
- int _client_port;
- int32_t _id;
-};
-
-
-} // namespace Client
-} // namespace Ingen
-
-#endif // OSCENGINEINTERFACE_H
-
diff --git a/src/libs/client/OSCEngineSender.cpp b/src/libs/client/OSCEngineSender.cpp
new file mode 100644
index 00000000..cc70dc8e
--- /dev/null
+++ b/src/libs/client/OSCEngineSender.cpp
@@ -0,0 +1,348 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OSCEngineSender.h"
+#include "interface/ClientKey.h"
+
+namespace Ingen {
+namespace Client {
+
+/** Note the sending port is implicitly set by liblo, lo_send by default sends
+ * from the most recently created server, so create the OSC listener before
+ * this to have it all happen on the same port. Yeah, this is a big magic :/
+ */
+OSCEngineSender::OSCEngineSender(const string& engine_url)
+: _engine_url(engine_url)
+, _engine_addr(lo_address_new_from_url(engine_url.c_str()))
+, _id(0)
+{
+}
+
+
+OSCEngineSender::~OSCEngineSender()
+{
+ lo_address_free(_engine_addr);
+}
+
+
+/* *** EngineInterface implementation below here *** */
+
+
+/** Register with the engine via OSC.
+ *
+ * Note that this does not actually use 'key', since the engine creates
+ * it's own key for OSC clients (namely the incoming URL), for NAT
+ * traversal. It is a parameter to remain compatible with EngineInterface.
+ */
+void
+OSCEngineSender::register_client(ClientKey key, CountedPtr client)
+{
+ // FIXME: use parameters.. er, somehow.
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/register_client", "i", next_id());
+}
+
+
+void
+OSCEngineSender::unregister_client(ClientKey key)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/unregister_client", "i", next_id());
+}
+
+
+
+// Engine commands
+void
+OSCEngineSender::load_plugins()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/load_plugins", "i", next_id());
+}
+
+
+void
+OSCEngineSender::activate()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/activate", "i", next_id());
+}
+
+
+void
+OSCEngineSender::deactivate()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/deactivate", "i", next_id());
+}
+
+
+void
+OSCEngineSender::quit()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/engine/quit", "i", next_id());
+}
+
+
+
+// Object commands
+
+void
+OSCEngineSender::create_patch(const string& path,
+ uint32_t poly)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/create_patch", "isi",
+ next_id(),
+ path.c_str(),
+ poly);
+}
+
+
+void
+OSCEngineSender::create_port(const string& path,
+ const string& data_type,
+ bool is_output)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/create_port", "issi",
+ next_id(),
+ path.c_str(),
+ data_type.c_str(),
+ (is_output ? 1 : 0));
+}
+
+
+void
+OSCEngineSender::create_node(const string& path,
+ const string& plugin_type,
+ const string& plugin_uri,
+ bool polyphonic)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/create_node", "isssi",
+ next_id(),
+ path.c_str(),
+ plugin_type.c_str(),
+ plugin_uri.c_str(),
+ (polyphonic ? 1 : 0));
+}
+
+
+void
+OSCEngineSender::rename(const string& old_path,
+ const string& new_name)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/rename", "iss",
+ next_id(),
+ old_path.c_str(),
+ new_name.c_str());
+}
+
+
+void
+OSCEngineSender::destroy(const string& path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/destroy", "is",
+ next_id(),
+ path.c_str());
+}
+
+
+void
+OSCEngineSender::clear_patch(const string& patch_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/clear_patch", "is",
+ next_id(),
+ patch_path.c_str());
+}
+
+
+void
+OSCEngineSender::enable_patch(const string& patch_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/enable_patch", "is",
+ next_id(),
+ patch_path.c_str());
+}
+
+
+void
+OSCEngineSender::disable_patch(const string& patch_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/disable_patch", "is",
+ next_id(),
+ patch_path.c_str());
+}
+
+
+void
+OSCEngineSender::connect(const string& src_port_path,
+ const string& dst_port_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/connect", "iss",
+ next_id(),
+ src_port_path.c_str(),
+ dst_port_path.c_str());
+}
+
+
+void
+OSCEngineSender::disconnect(const string& src_port_path,
+ const string& dst_port_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/disconnect", "iss",
+ next_id(),
+ src_port_path.c_str(),
+ dst_port_path.c_str());
+}
+
+
+void
+OSCEngineSender::disconnect_all(const string& node_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/disconnect_all", "is",
+ next_id(),
+ node_path.c_str());
+}
+
+
+void
+OSCEngineSender::set_port_value(const string& port_path,
+ float val)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/set_port_value", "isf",
+ next_id(),
+ port_path.c_str(),
+ val);
+}
+
+
+void
+OSCEngineSender::set_port_value(const string& port_path,
+ uint32_t voice,
+ float val)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/set_port_value", "isif",
+ next_id(),
+ port_path.c_str(),
+ voice,
+ val);
+}
+
+
+void
+OSCEngineSender::set_port_value_queued(const string& port_path,
+ float val)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/set_port_value_queued", "isf",
+ next_id(),
+ port_path.c_str(),
+ val);
+}
+
+
+void
+OSCEngineSender::set_program(const string& node_path,
+ uint32_t bank,
+ uint32_t program)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr,
+ (string("/dssi") + node_path + "/program").c_str(),
+ "ii",
+ bank,
+ program);
+}
+
+
+void
+OSCEngineSender::midi_learn(const string& node_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/synth/midi_learn", "is",
+ next_id(),
+ node_path.c_str());
+}
+
+
+void
+OSCEngineSender::set_metadata(const string& obj_path,
+ const string& predicate,
+ const string& value)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/metadata/set", "isss",
+ next_id(),
+ obj_path.c_str(),
+ predicate.c_str(),
+ value.c_str());
+}
+
+
+// Requests //
+
+void
+OSCEngineSender::ping()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/ping", "i", next_id());
+}
+
+
+void
+OSCEngineSender::request_port_value(const string& port_path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/request/port_value", "is",
+ next_id(),
+ port_path.c_str());
+}
+
+
+void
+OSCEngineSender::request_plugins()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/request/plugins", "i", next_id());
+}
+
+
+void
+OSCEngineSender::request_all_objects()
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/request/all_objects", "i", next_id());
+}
+
+
+
+} // namespace Client
+} // namespace Ingen
+
+
diff --git a/src/libs/client/OSCEngineSender.h b/src/libs/client/OSCEngineSender.h
new file mode 100644
index 00000000..184c0569
--- /dev/null
+++ b/src/libs/client/OSCEngineSender.h
@@ -0,0 +1,145 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OSCENGINESENDER_H
+#define OSCENGINESENDER_H
+
+#include
+#include
+#include
+#include "interface/EngineInterface.h"
+using std::string;
+using Ingen::Shared::EngineInterface;
+using Ingen::Shared::ClientInterface;
+using Ingen::Shared::ClientKey;
+
+
+namespace Ingen {
+namespace Client {
+
+/* OSC (via liblo) interface to the engine.
+ *
+ * Clients can use this opaquely as an EngineInterface* to control the engine
+ * over OSC (whether over a network or not, etc).
+ *
+ * \ingroup IngenClient
+ */
+class OSCEngineSender : public EngineInterface
+{
+public:
+ OSCEngineSender(const string& engine_url);
+
+ ~OSCEngineSender();
+
+ string engine_url() { return _engine_url; }
+
+ inline size_t next_id()
+ { if (_id != -1) { _id = (_id == -2) ? 0 : _id+1; } return _id; }
+
+ void enable_responses() { _id = 0; }
+ void disable_responses() { _id = -1; }
+
+
+ /* *** EngineInterface implementation below here *** */
+
+ // Client registration
+ void register_client(ClientKey key, CountedPtr client);
+ void unregister_client(ClientKey key);
+
+
+ // Engine commands
+ void load_plugins();
+ void activate();
+ void deactivate();
+ void quit();
+
+
+ // Object commands
+
+ void create_patch(const string& path,
+ uint32_t poly);
+
+ void create_port(const string& path,
+ const string& data_type,
+ bool is_output);
+
+ void create_node(const string& path,
+ const string& plugin_type,
+ const string& plugin_uri,
+ bool polyphonic);
+
+ void rename(const string& old_path,
+ const string& new_name);
+
+ void destroy(const string& path);
+
+ void clear_patch(const string& patch_path);
+
+ void enable_patch(const string& patch_path);
+
+ void disable_patch(const string& patch_path);
+
+ void connect(const string& src_port_path,
+ const string& dst_port_path);
+
+ void disconnect(const string& src_port_path,
+ const string& dst_port_path);
+
+ void disconnect_all(const string& node_path);
+
+ void set_port_value(const string& port_path,
+ float val);
+
+ void set_port_value(const string& port_path,
+ uint32_t voice,
+ float val);
+
+ void set_port_value_queued(const string& port_path,
+ float val);
+
+ void set_program(const string& node_path,
+ uint32_t bank,
+ uint32_t program);
+
+ void midi_learn(const string& node_path);
+
+ void set_metadata(const string& obj_path,
+ const string& predicate,
+ const string& value);
+
+ // Requests //
+
+ void ping();
+
+ void request_port_value(const string& port_path);
+
+ void request_plugins();
+
+ void request_all_objects();
+
+protected:
+ string _engine_url;
+ lo_address _engine_addr;
+ int _client_port;
+ int32_t _id;
+};
+
+
+} // namespace Client
+} // namespace Ingen
+
+#endif // OSCENGINESENDER_H
+
diff --git a/src/libs/client/OSCListener.cpp b/src/libs/client/OSCListener.cpp
deleted file mode 100644
index c63ffd85..00000000
--- a/src/libs/client/OSCListener.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "OSCListener.h"
-//#include "NodeModel.h"
-//#include "PluginModel.h"
-#include
-#include
-#include
-#include
-using std::cerr; using std::cout; using std::endl;
-
-namespace Ingen {
-namespace Client {
-
-
-/** Construct a OSCListener with a user-provided ModelClientInterface object for notification
- * of engine events.
- */
-OSCListener::OSCListener(int listen_port)
-: _listen_port(listen_port),
- _st(NULL)//,
-// _receiving_node(false),
-// _receiving_node_model(NULL),
-// _receiving_node_num_ports(0),
-// _num_received_ports(0)
-{
- start();
-}
-
-
-OSCListener::~OSCListener()
-{
- stop();
-}
-
-
-void
-OSCListener::start()
-{
- if (_st != NULL)
- return;
-
- if (_listen_port == 0) {
- _st = lo_server_thread_new(NULL, error_cb);
- _listen_port = lo_server_thread_get_port(_st);
- } else {
- char port_str[8];
- snprintf(port_str, 8, "%d", _listen_port);
- _st = lo_server_thread_new(port_str, error_cb);
- }
-
- if (_st == NULL) {
- cerr << "[OSCListener] Could not start OSC listener. Aborting." << endl;
- exit(EXIT_FAILURE);
- } else {
- cout << "[OSCListener] Started OSC listener on port " << lo_server_thread_get_port(_st) << endl;
- }
-
- // FIXME
- lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL);
-
- //lo_server_thread_add_method(_st, "/om/response/ok", "i", om_response_ok_cb, this);
- //lo_server_thread_add_method(_st, "/om/response/error", "is", om_responseerror_cb, this);
-
- setup_callbacks();
-
- // Display any uncaught messages to the console
- //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL);
-
- lo_server_thread_start(_st);
-}
-
-
-void
-OSCListener::stop()
-{
- if (_st != NULL) {
- //unregister_client();
- lo_server_thread_free(_st);
- _st = NULL;
- }
-}
-
-
-int
-OSCListener::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data)
-{
- printf("[OSCMsg] %s (%s)\t", path, types);
-
- for (int i=0; i < argc; ++i) {
- lo_arg_pp(lo_type(types[i]), argv[i]);
- printf("\t");
- }
- printf("\n");
-
- /*for (int i=0; i < argc; ++i) {
- printf(" '%c' ", types[i]);
- lo_arg_pp(lo_type(types[i]), argv[i]);
- printf("\n");
- }
- printf("\n");*/
-
- return 1; // not handled
-}
-
-
-void
-OSCListener::error_cb(int num, const char* msg, const char* path)
-{
- cerr << "Got error from server: " << msg << endl;
-}
-
-
-
-int
-OSCListener::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data)
-{
- string msg = "Received unknown OSC message: ";
- msg += path;
-
- cerr << msg << endl;
-
- return 0;
-}
-
-
-void
-OSCListener::setup_callbacks()
-{
- lo_server_thread_add_method(_st, "/om/num_plugins", "i", num_plugins_cb, this);
- lo_server_thread_add_method(_st, "/om/plugin", "sss", plugin_cb, this);
- lo_server_thread_add_method(_st, "/om/new_patch", "si", new_patch_cb, this);
- lo_server_thread_add_method(_st, "/om/destroyed", "s", destroyed_cb, this);
- lo_server_thread_add_method(_st, "/om/patch_enabled", "s", patch_enabled_cb, this);
- lo_server_thread_add_method(_st, "/om/patch_disabled", "s", patch_disabled_cb, this);
- lo_server_thread_add_method(_st, "/om/patch_cleared", "s", patch_cleared_cb, this);
- lo_server_thread_add_method(_st, "/om/object_renamed", "ss", object_renamed_cb, this);
- lo_server_thread_add_method(_st, "/om/new_connection", "ss", connection_cb, this);
- lo_server_thread_add_method(_st, "/om/disconnection", "ss", disconnection_cb, this);
- lo_server_thread_add_method(_st, "/om/new_node", "sssii", new_node_cb, this);
- lo_server_thread_add_method(_st, "/om/new_port", "ssi", new_port_cb, this);
- lo_server_thread_add_method(_st, "/om/metadata/update", "sss", metadata_update_cb, this);
- lo_server_thread_add_method(_st, "/om/control_change", "sf", control_change_cb, this);
- lo_server_thread_add_method(_st, "/om/program_add", "siis", program_add_cb, this);
- lo_server_thread_add_method(_st, "/om/program_remove", "sii", program_remove_cb, this);
-}
-
-
-/** Catches errors that aren't a direct result of a client request.
- */
-int
-OSCListener::m_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- cerr << "ERROR: " << argv[0]->s << endl;
- // FIXME
- //error((char*)argv[0]);
- return 0;
-}
-
-
-int
-OSCListener::m_new_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- new_patch(&argv[0]->s, argv[1]->i); // path, poly
- return 0;
-}
-
-
-int
-OSCListener::m_destroyed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- object_destroyed((const char*)&argv[0]->s);
- return 0;
-}
-
-
-int
-OSCListener::m_patch_enabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- patch_enabled((const char*)&argv[0]->s);
- return 0;
-}
-
-
-int
-OSCListener::m_patch_disabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- patch_disabled((const char*)&argv[0]->s);
- return 0;
-}
-
-
-int
-OSCListener::m_patch_cleared_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- patch_cleared((const char*)&argv[0]->s);
- return 0;
-}
-
-
-int
-OSCListener::m_object_renamed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- object_renamed((const char*)&argv[0]->s, (const char*)&argv[1]->s);
- return 0;
-}
-
-
-int
-OSCListener::m_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* const src_port_path = &argv[0]->s;
- const char* const dst_port_path = &argv[1]->s;
-
- connection(src_port_path, dst_port_path);
-
- return 0;
-}
-
-
-int
-OSCListener::m_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* src_port_path = &argv[0]->s;
- const char* dst_port_path = &argv[1]->s;
-
- disconnection(src_port_path, dst_port_path);
-
- return 0;
-}
-
-
-/** Notification of a new node creation.
- */
-int
-OSCListener::m_new_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* type = &argv[0]->s;
- const char* uri = &argv[1]->s;
- const char* node_path = &argv[2]->s;
- const int32_t poly = argv[3]->i;
- const int32_t num_ports = argv[4]->i;
-
- new_node(type, uri, node_path, poly, num_ports);
-
- /*_receiving_node_model = new NodeModel(node_path);
- _receiving_node_model->polyphonic((poly == 1));
- _receiving_node_num_ports = num_ports;
-
- PluginModel* pi = new PluginModel(type, uri);
- _receiving_node_model->plugin(pi);
-
- _receiving_node = true;
- _num_received_ports = 0;
- */
- return 0;
-}
-
-
-/** Notification of a new port creation.
- */
-int
-OSCListener::m_new_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[0]->s;
- const char* type = &argv[1]->s;
- bool is_output = (argv[2]->i == 1);
- /*const char* direction = &argv[2]->s;
- const char* hint = &argv[3]->s;
- float default_val = argv[4]->f;
- float min_val = argv[5]->f;
- float max_val = argv[6]->f;*/
-
- new_port(port_path, type, is_output);
-#if 0
- PortModel::Type ptype = PortModel::CONTROL;
- if (!strcmp(type, "AUDIO")) ptype = PortModel::AUDIO;
- else if (!strcmp(type, "CONTROL")) ptype = PortModel::CONTROL;
- else if (!strcmp(type, "MIDI")) ptype = PortModel::MIDI;
- else cerr << "[OSCListener] WARNING: Unknown port type received (" << type << ")" << endl;
-
-#if 0
- PortModel::Direction pdir = PortModel::INPUT;
- if (!strcmp(direction, "INPUT")) pdir = PortModel::INPUT;
- else if (!strcmp(direction, "OUTPUT")) pdir = PortModel::OUTPUT;
- else cerr << "[OSCListener] WARNING: Unknown port direction received (" << direction << ")" << endl;
-#endif
- PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT;
-
-/*
- PortModel::Hint phint = PortModel::NONE;
- if (!strcmp(hint, "LOGARITHMIC")) phint = PortModel::LOGARITHMIC;
- else if (!strcmp(hint, "INTEGER")) phint = PortModel::INTEGER;
- else if (!strcmp(hint, "TOGGLE")) phint = PortModel::TOGGLE;
-
- PortModel* port_model = new PortModel(port_path, ptype, pdir, phint, default_val, min_val, max_val);
-*/
- PortModel* port_model = new PortModel(port_path, ptype, pdir);
- if (m_receiving_node) {
- assert(m_receiving_node_model);
- m_receiving_node_model->add_port(port_model);
- ++m_num_received_ports;
-
- // If transmission is done, send new node to client
- if (m_num_received_ports == m_receiving_node_num_ports) {
- new_node_model(m_receiving_node_model);
- m_receiving_node = false;
- m_receiving_node_model = NULL;
- m_num_received_ports = 0;
- }
- } else {
- new_port_model(port_model);
- }
-
-#endif
- return 0;
-}
-
-
-/** Notification of a new or updated piece of metadata.
- */
-int
-OSCListener::m_metadata_update_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* obj_path = &argv[0]->s;
- const char* key = &argv[1]->s;
- const char* value = &argv[2]->s;
-
- metadata_update(obj_path, key, value);
-
- return 0;
-}
-
-
-int
-OSCListener::m_control_change_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* const port_path = &argv[0]->s;
- const float value = argv[1]->f;
-
- control_change(port_path, value);
-
- return 0;
-}
-
-
-/** Number of plugins in engine, should precede /om/plugin messages in response
- * to a /om/send_plugins
- */
-int
-OSCListener::m_num_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- /** Not worth it implementing a ModelClientInterface callback for this (?)
- * Or I'm just lazy. FIXME? */
- num_plugins(argv[0]->i);
-
- return 0;
-}
-
-
-/** A plugin info response from the server, in response to a /send_plugins
- */
-int
-OSCListener::m_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- assert(argc == 3 && !strcmp(types, "sss"));
- new_plugin(&argv[0]->s, &argv[1]->s, &argv[2]->s); // type, uri
-
- return 0;
-}
-
-
-int
-OSCListener::m_program_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[0]->s;
- int32_t bank = argv[1]->i;
- int32_t program = argv[2]->i;
- const char* name = &argv[3]->s;
-
- program_add(node_path, bank, program, name);
-
- return 0;
-}
-
-
-int
-OSCListener::m_program_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[0]->s;
- int32_t bank = argv[1]->i;
- int32_t program = argv[2]->i;
-
- program_remove(node_path, bank, program);
-
- return 0;
-}
-
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/libs/client/OSCListener.h b/src/libs/client/OSCListener.h
deleted file mode 100644
index 3e9d165d..00000000
--- a/src/libs/client/OSCListener.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-#ifndef OSCLISTENER_H
-#define OSCLISTENER_H
-
-#include
-#include
-#include "interface/ClientInterface.h"
-
-namespace Ingen {
-
-/** Client library */
-namespace Client {
-
-//class NodeModel;
-//class PresetModel;
-
-/* Some boilerplate killing macros... */
-#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg
-
-/* Defines a static handler to be passed to lo_add_method, which is a trivial
- * wrapper around a non-static method that does the real work. Makes a whoole
- * lot of ugly boiler plate go away */
-#define LO_HANDLER(name) \
-int m_##name##_cb (LO_HANDLER_ARGS);\
-inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\
-{ return ((OSCListener*)osc_listener)->m_##name##_cb(path, types, argv, argc, msg); }
-
-
-/** Callbacks for "notification band" OSC messages.
- *
- * Receives all notification of engine state, but not replies on the "control
- * band". See OSC namespace documentation for details.
- *
- * Right now this class and Comm share the same lo_server_thread and the barrier
- * between them is a bit odd, but eventually this class will be able to listen
- * on a completely different port (ie have it's own lo_server_thread) to allow
- * things like listening to the notification band over TCP while sending commands
- * on the control band over UDP.
- *
- * \ingroup IngenClient
- */
-class OSCListener : virtual public Ingen::Shared::ClientInterface
-{
-public:
- OSCListener(int listen_port);
- ~OSCListener();
-
- void start();
- void stop();
-
- int listen_port() { return _listen_port; }
- string listen_url() { return lo_server_thread_get_url(_st); }
-
-private:
- // Prevent copies
- OSCListener(const OSCListener& copy);
- OSCListener& operator=(const OSCListener& copy);
-
- void setup_callbacks();
-
- static void error_cb(int num, const char* msg, const char* path);
- static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data);
- static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver);
- /*
- inline static int om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm);
- int m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data);
- inline static int om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm);
- int m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data);
-*/
- int _listen_port;
- lo_server_thread _st;
-
- // Used for receiving nodes - multiple messages are received before
- // sending an event to the client (via ModelClientInterface)
- //bool _receiving_node;
- //NodeModel* _receiving_node_model;
- //int32_t _receiving_node_num_ports;
- //int32_t _num_received_ports;
-
- LO_HANDLER(error);
- LO_HANDLER(num_plugins);
- LO_HANDLER(plugin);
- LO_HANDLER(plugin_list_end);
- LO_HANDLER(new_patch);
- LO_HANDLER(destroyed);
- LO_HANDLER(patch_enabled);
- LO_HANDLER(patch_disabled);
- LO_HANDLER(patch_cleared);
- LO_HANDLER(object_renamed);
- LO_HANDLER(connection);
- LO_HANDLER(disconnection);
- LO_HANDLER(new_node);
- LO_HANDLER(new_port);
- LO_HANDLER(metadata_update);
- LO_HANDLER(control_change);
- LO_HANDLER(program_add);
- LO_HANDLER(program_remove);
-};
-
-
-} // namespace Client
-
-} // namespace Ingen
-
-#endif // OSCLISTENER_H
diff --git a/src/libs/client/OSCModelEngineInterface.cpp b/src/libs/client/OSCModelEngineInterface.cpp
index 2e831705..14f2fe3a 100644
--- a/src/libs/client/OSCModelEngineInterface.cpp
+++ b/src/libs/client/OSCModelEngineInterface.cpp
@@ -21,7 +21,7 @@
#include
#include
#include
-#include "OSCListener.h"
+#include "OSCClientReceiver.h"
#include "PatchModel.h"
#include "ConnectionModel.h"
#include "PresetModel.h"
@@ -39,7 +39,7 @@ namespace Client {
* of engine events.
*/
OSCModelEngineInterface::OSCModelEngineInterface(const string& engine_url)
-: OSCEngineInterface(engine_url),
+: OSCEngineSender(engine_url),
m_request_id(0),
m_is_attached(false),
m_is_registered(false)
diff --git a/src/libs/client/OSCModelEngineInterface.h b/src/libs/client/OSCModelEngineInterface.h
index a2172e23..f600fb8f 100644
--- a/src/libs/client/OSCModelEngineInterface.h
+++ b/src/libs/client/OSCModelEngineInterface.h
@@ -21,7 +21,7 @@
#include
#include "util/Semaphore.h"
#include "interface/EngineInterface.h"
-#include "OSCEngineInterface.h"
+#include "OSCEngineSender.h"
#include "ModelEngineInterface.h"
using std::string;
@@ -34,29 +34,22 @@ namespace Client {
class NodeModel;
class PresetModel;
class PatchModel;
-class OSCListener;
class ModelClientInterface;
/** Old model-based OSC engine command interface.
*
* This is an old class from before when the well-defined interfaces between
- * engine and client were defined. I've wrapped it around OSCEngineInterface
+ * engine and client were defined. I've wrapped it around OSCEngineSender
* so all the common functions are implemented there, and implemented the
* remaining functions using those, for compatibility. Hopefully something
* better gets figured out and this can go away completely, but for now this
* gets the existing clients working through EngineInterface in the easiest
* way possible. This class needs to die.
*
- * Old comment:
- * Handles all OSC communication on the "control band". For the time being,
- * manages the OSCListener which handles the "notification band", but this
- * will change in the future (for complete separation). See OSC namespace
- * documentation for more details.
- *
* \ingroup IngenClient
*/
-class OSCModelEngineInterface : public OSCEngineInterface, public ModelEngineInterface
+class OSCModelEngineInterface : public OSCEngineSender, public ModelEngineInterface
{
public:
//OSCModelEngineInterface(ModelClientInterface* const client_hooks, const string& engine_url);
diff --git a/src/libs/client/Store.cpp b/src/libs/client/Store.cpp
index 403264f2..219ea13f 100644
--- a/src/libs/client/Store.cpp
+++ b/src/libs/client/Store.cpp
@@ -297,7 +297,7 @@ Store::new_port_event(const string& path, const string& type, bool is_output)
if (type == "AUDIO") ptype = PortModel::AUDIO;
else if (type == "CONTROL") ptype = PortModel::CONTROL;
else if (type== "MIDI") ptype = PortModel::MIDI;
- else cerr << "[OSCListener] WARNING: Unknown port type received (" << type << ")" << endl;
+ else cerr << "[Store] WARNING: Unknown port type received (" << type << ")" << endl;
PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT;
diff --git a/src/libs/engine/ClientBroadcaster.cpp b/src/libs/engine/ClientBroadcaster.cpp
index 1fa64d9a..355d4232 100644
--- a/src/libs/engine/ClientBroadcaster.cpp
+++ b/src/libs/engine/ClientBroadcaster.cpp
@@ -30,7 +30,7 @@
#include "ObjectSender.h"
#include "interface/ClientKey.h"
#include "interface/ClientInterface.h"
-#include "OSCClient.h"
+#include "OSCClientSender.h"
using std::cout; using std::cerr; using std::endl;
using Ingen::Shared::ClientInterface;
@@ -137,6 +137,10 @@ ClientBroadcaster::send_plugins_to(ClientInterface* client, const list&
const Plugin* plugin;
+ // FIXME FIXME FIXME
+ OSCClientSender* osc_client = dynamic_cast(client);
+ assert(osc_client);
+
lo_timetag tt;
lo_timetag_now(&tt);
lo_bundle b = lo_bundle_new(tt);
@@ -157,16 +161,14 @@ ClientBroadcaster::send_plugins_to(ClientInterface* client, const list&
lo_bundle_add_message(b, "/om/plugin", m);
msgs.push_back(m);
if (lo_bundle_length(b) > 1024) {
- // FIXME FIXME FIXME dirty, dirty cast
- lo_send_bundle(((OSCClient*)client)->address(), b);
+ lo_send_bundle(osc_client->address(), b);
lo_bundle_free(b);
b = lo_bundle_new(tt);
}
}
if (lo_bundle_length(b) > 0) {
- // FIXME FIXME FIXME dirty, dirty cast
- lo_send_bundle(((OSCClient*)client)->address(), b);
+ lo_send_bundle(osc_client->address(), b);
lo_bundle_free(b);
} else {
lo_bundle_free(b);
diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp
index a98f4fbf..ebe8e4f7 100644
--- a/src/libs/engine/Engine.cpp
+++ b/src/libs/engine/Engine.cpp
@@ -24,7 +24,6 @@
#include "util/Queue.h"
#include "JackAudioDriver.h"
#include "NodeFactory.h"
-#include "OSCReceiver.h"
#include "ClientBroadcaster.h"
#include "Patch.h"
#include "ObjectStore.h"
@@ -49,9 +48,9 @@ using std::cout; using std::cerr; using std::endl;
namespace Ingen {
-Engine::Engine(const char* listen_port, AudioDriver* audio_driver)
-: m_audio_driver( (audio_driver) ? audio_driver : new JackAudioDriver(*this) ),
- m_osc_receiver(new OSCReceiver(*this, pre_processor_queue_size, listen_port)),
+Engine::Engine(AudioDriver* audio_driver)
+: m_event_source(NULL),
+ m_audio_driver( (audio_driver) ? audio_driver : new JackAudioDriver(*this) ),
#ifdef HAVE_JACK_MIDI
m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())),
#elif HAVE_ALSA_MIDI
@@ -72,7 +71,6 @@ Engine::Engine(const char* listen_port, AudioDriver* audio_driver)
m_quit_flag(false),
m_activated(false)
{
- m_osc_receiver->activate();
}
@@ -88,7 +86,6 @@ Engine::~Engine()
delete m_object_store;
delete m_client_broadcaster;
- delete m_osc_receiver;
delete m_node_factory;
delete m_midi_driver;
delete m_audio_driver;
@@ -183,7 +180,6 @@ Engine::deactivate()
if (m_midi_driver != NULL)
m_midi_driver->deactivate();
- m_osc_receiver->deactivate();
m_audio_driver->deactivate();
// Finalize any lingering events (unlikely)
diff --git a/src/libs/engine/Engine.h b/src/libs/engine/Engine.h
index fbad649f..35192bb5 100644
--- a/src/libs/engine/Engine.h
+++ b/src/libs/engine/Engine.h
@@ -27,7 +27,6 @@ namespace Ingen {
class AudioDriver;
class MidiDriver;
class NodeFactory;
-class OSCReceiver;
class ClientBroadcaster;
class Patch;
class ObjectStore;
@@ -51,7 +50,7 @@ template class Driver;
class Engine
{
public:
- Engine(const char* listen_port, AudioDriver* audio_driver = 0);
+ Engine(AudioDriver* audio_driver = 0);
~Engine();
int main();
@@ -63,8 +62,10 @@ public:
void activate();
void deactivate();
+ void set_event_source(EventSource* es) { m_event_source = es; }
+
+ EventSource* event_source() const { return m_event_source; }
AudioDriver* audio_driver() const { return m_audio_driver; }
- OSCReceiver* osc_receiver() const { return m_osc_receiver; }
MidiDriver* midi_driver() const { return m_midi_driver; }
Maid* maid() const { return m_maid; }
PostProcessor* post_processor() const { return m_post_processor; }
@@ -81,8 +82,8 @@ private:
Engine(const Engine&);
Engine& operator=(const Engine&);
+ EventSource* m_event_source;
AudioDriver* m_audio_driver;
- OSCReceiver* m_osc_receiver;
MidiDriver* m_midi_driver;
Maid* m_maid;
PostProcessor* m_post_processor;
diff --git a/src/libs/engine/EventSource.h b/src/libs/engine/EventSource.h
index 212249c6..d251cac5 100644
--- a/src/libs/engine/EventSource.h
+++ b/src/libs/engine/EventSource.h
@@ -17,10 +17,13 @@
#ifndef EVENTSOURCE_H
#define EVENTSOURCE_H
+#include "types.h"
+
namespace Ingen {
class Event;
class QueuedEvent;
+class PostProcessor;
/** Source for events to run in the audio thread.
@@ -41,9 +44,7 @@ public:
virtual ~EventSource() {}
- virtual Event* pop_earliest_queued_before(const SampleCount time) = 0;
-
- virtual Event* pop_earliest_stamped_before(const SampleCount time) = 0;
+ virtual void process(PostProcessor& dest, SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end) = 0;
protected:
EventSource() {}
diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp
index 2c0d4a70..66a16d51 100644
--- a/src/libs/engine/JackAudioDriver.cpp
+++ b/src/libs/engine/JackAudioDriver.cpp
@@ -24,7 +24,6 @@
#include "Event.h"
#include "QueuedEvent.h"
#include "EventSource.h"
-#include "OSCReceiver.h"
#include "PostProcessor.h"
#include "util/Queue.h"
#include "Node.h"
@@ -33,6 +32,7 @@
#include "MidiDriver.h"
#include "List.h"
#include "DuplexPort.h"
+#include "EventSource.h"
#ifdef HAVE_LASH
#include "LashDriver.h"
#endif
@@ -181,8 +181,6 @@ void
JackAudioDriver::deactivate()
{
if (_is_activated) {
- _engine.osc_receiver()->deactivate();
-
jack_deactivate(_client);
_is_activated = false;
@@ -242,48 +240,6 @@ JackAudioDriver::create_port(DuplexPort* patch_port)
}
-/** Process all the pending events for this cycle.
- *
- * Called from the realtime thread once every process cycle.
- */
-void
-JackAudioDriver::process_events(SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end)
-{
- Event* ev = NULL;
-
- /* Limit the maximum number of queued events to process per cycle. This
- * makes the process callback (more) realtime-safe by preventing being
- * choked by events coming in faster than they can be processed.
- * FIXME: run the math on this and figure out a good value */
- const unsigned int MAX_QUEUED_EVENTS = _buffer_size / 100;
-
- unsigned int num_events_processed = 0;
-
- // Process the "slow" events first, because it's possible some of the
- // RT events depend on them
-
- /* FIXME: Merge these next two loops into one */
-
- // FIXME
- while ((ev = _engine.osc_receiver()->pop_earliest_queued_before(cycle_end))) {
- ev->execute(nframes, cycle_start, cycle_end);
- _engine.post_processor()->push(ev);
- if (++num_events_processed > MAX_QUEUED_EVENTS)
- break;
- }
-
- while ((ev = _engine.osc_receiver()->pop_earliest_stamped_before(cycle_end))) {
- ev->execute(nframes, cycle_start, cycle_end);
- _engine.post_processor()->push(ev);
- ++num_events_processed;
- }
-
- if (num_events_processed > 0)
- _engine.post_processor()->whip();
-}
-
-
-
/**** Jack Callbacks ****/
@@ -313,7 +269,9 @@ JackAudioDriver::_process_cb(jack_nframes_t nframes)
_transport_state = jack_transport_query(_client, &_position);
- process_events(nframes, start_of_last_cycle, start_of_current_cycle);
+ if (_engine.event_source())
+ _engine.event_source()->process(*_engine.post_processor(), nframes, start_of_last_cycle, start_of_current_cycle);
+
_engine.midi_driver()->prepare_block(start_of_last_cycle, start_of_current_cycle);
// Set buffers of patch ports to Jack port buffers (zero-copy processing)
diff --git a/src/libs/engine/JackAudioDriver.h b/src/libs/engine/JackAudioDriver.h
index aa0cebbc..072434b9 100644
--- a/src/libs/engine/JackAudioDriver.h
+++ b/src/libs/engine/JackAudioDriver.h
@@ -84,8 +84,6 @@ public:
void enable();
void disable();
- void process_events(SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end);
-
DriverPort* create_port(DuplexPort* patch_port);
Patch* root_patch() { return _root_patch; }
diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am
index bc2560eb..1f3b4d45 100644
--- a/src/libs/engine/Makefile.am
+++ b/src/libs/engine/Makefile.am
@@ -23,8 +23,8 @@ libingen_la_SOURCES = \
Engine.cpp \
JackAudioDriver.h \
JackAudioDriver.cpp \
- OSCReceiver.h \
- OSCReceiver.cpp \
+ OSCEngineReceiver.h \
+ OSCEngineReceiver.cpp \
Responder.h \
OSCResponder.h \
OSCResponder.cpp \
@@ -33,8 +33,8 @@ libingen_la_SOURCES = \
ClientBroadcaster.cpp \
ObjectSender.h \
ObjectSender.cpp \
- OSCClient.h \
- OSCClient.cpp \
+ OSCClientSender.h \
+ OSCClientSender.cpp \
Buffer.h \
Buffer.cpp \
Port.h \
diff --git a/src/libs/engine/OSCClient.cpp b/src/libs/engine/OSCClient.cpp
deleted file mode 100644
index acc56cdf..00000000
--- a/src/libs/engine/OSCClient.cpp
+++ /dev/null
@@ -1,500 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "OSCClient.h"
-#include
-#include
-#include
-#include "ObjectStore.h"
-#include "NodeFactory.h"
-#include "util.h"
-#include "Patch.h"
-#include "Node.h"
-#include "Plugin.h"
-#include "TypedPort.h"
-#include "Connection.h"
-#include "AudioDriver.h"
-#include "interface/ClientInterface.h"
-#include "Responder.h"
-
-using std::cout; using std::cerr; using std::endl;
-
-namespace Ingen {
-
-
-/*! \page client_osc_namespace Client OSC Namespace Documentation
- *
- * These are all the messages sent from the engine to the client.
- * Communication takes place over two distinct bands: control band and
- * notification band.
- * The control band is where clients send commands, and receive a simple
- * response, either OK or an error.
- * All notifications of engine state (ie new nodes) are sent over the
- * notification band which is seperate from the control band. The
- * reasoning behind this is that many clients may be connected at the same
- * time - a client may receive notifications that are not a direct consequence
- * of some message it sent.
- * The notification band can be thought of as a stream of events representing
- * the changing engine state. For example, It is possible for a client to send
- * commands and receive aknowledgements, and not listen to the notification band
- * at all; or (in the near future anyway) for a client to use UDP for the control
- * band (for speed), and TCP for the notification band (for reliability and
- * order guarantees).
- * \n\n
- */
-
-
-/* Documentation for namespace portion implemented in Responder.cpp */
-
-/** \page client_osc_namespace
- * \n
- * Notification Band
- */
-
-/** \page client_osc_namespace
- * \b /om/response/ok - Respond successfully to a user command
- * \arg \b responder-id (int) - Responder ID this is a response to
- *
\n \n
- */
-
-/** \page client_osc_namespace
- * \b /om/response/error - Respond negatively to a user command
- * \arg \b responder-id (int) - Request ID this is a response to
- * \arg \b message (string) - Error message (natural language text)
- *
\n \n
- */
-
-
-
-/** \page client_osc_namespace
- * \n
- * Notification Band
- */
-
-/** \page client_osc_namespace
- * \b /om/error - Notification that an error has occurred
- * \arg \b message (string) - Error message (natural language text)
- *
- * \li This is for notification of errors that aren't a direct response to a
- * user command, ie "unexpected" errors.
\n \n
- */
-void
-OSCClient::error(const string& msg)
-{
- lo_send(_address, "/om/error", "s", msg.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/num_plugins
- * \arg \b num (int) - Number of plugins engine has loaded
- * \li This is sent before sending the list of plugins, so the client is aware
- * of how many plugins (/om/plugin messages) to expect.
\n \n
- */
-
-
-/** \page client_osc_namespace
- * \b /om/num_plugins
- * \arg \b num (int) - Number of plugins engine has loaded
- * \li This is sent before sending the list of plugins, so the client is aware
- * of how many plugins (/om/plugin messages) to expect.
\n \n
- */
-void
-OSCClient::num_plugins(uint32_t num)
-{
- lo_message m = lo_message_new();
- lo_message_add_int32(m, num);
- lo_send_message(_address, "/om/num_plugins", m);
-}
-
-
-/** \page client_osc_namespace
- * \b /om/plugin - Notification of the existance of a plugin
- * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")
- * \arg \b uri (string) - URI of the plugin (see engine namespace documentation) \n
- * \arg \b lib-name (string) - Name of shared library plugin resides in (ie "cmt.so")
- * \arg \b plug-label (string) - Label of the plugin (ie "dahdsr_iaoa")
- * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope")
- *
\n \n
- */
-/*
-void
-OSCClient::plugins()
-{
- Engine::instance().node_factory()->lock_plugin_list();
-
- const list& plugs = Engine::instance().node_factory()->plugins();
- const Plugin* plugin;
-
- lo_timetag tt;
- lo_timetag_now(&tt);
- lo_bundle b = lo_bundle_new(tt);
- lo_message m = lo_message_new();
- list msgs;
-
- lo_message_add_int32(m, plugs.size());
- lo_bundle_add_message(b, "/om/num_plugins", m);
- msgs.push_back(m);
-
- for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) {
- plugin = (*j);
- m = lo_message_new();
-
- lo_message_add_string(m, plugin->type_string());
- lo_message_add_string(m, plugin->uri().c_str());
- lo_message_add_string(m, plugin->plug_label().c_str());
- lo_message_add_string(m, plugin->name().c_str());
- lo_bundle_add_message(b, "/om/plugin", m);
- msgs.push_back(m);
- if (lo_bundle_length(b) > 1024) {
- lo_send_bundle(_address, b);
- lo_bundle_free(b);
- b = lo_bundle_new(tt);
- }
- }
-
- if (lo_bundle_length(b) > 0) {
- lo_send_bundle(_address, b);
- lo_bundle_free(b);
- } else {
- lo_bundle_free(b);
- }
- for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
- lo_message_free(*i);
-
- Engine::instance().node_factory()->unlock_plugin_list();
-}
-*/
-
-/** \page client_osc_namespace
- * \b /om/new_node - Notification of a new node's creation.
- * \arg \b plug-uri (string) - URI of the plugin new node is an instance of
- * \arg \b path (string) - Path of the new node
- * \arg \b polyphonic (integer-boolean) - Node is polyphonic (1 = yes, 0 = no)
- * \arg \b num-ports (integer) - Number of ports (number of new_port messages to expect)
- * \li New nodes are sent as a bundle. The first message in the bundle will be
- * this one (/om/new_node), followed by a series of /om/new_port commands,
- * followed by /om/new_node_end.
\n \n
- */
-void OSCClient::new_node(const string& plugin_type,
- const string& plugin_uri,
- const string& node_path,
- bool is_polyphonic,
- uint32_t num_ports)
-{
- lo_send(_address, "/om/new_node", "sssii", plugin_type.c_str(), plugin_uri.c_str(),
- node_path.c_str(), is_polyphonic ? 1 : 0, num_ports);
-#if 0
- /*
- lo_timetag tt;
- lo_timetag_now(&tt);
- lo_bundle b = lo_bundle_new(tt);
- lo_message m = lo_message_new();
- list msgs;
-
- lo_message_add_string(m, plugin_type.c_str());
- lo_message_add_string(m, plugin_uri.c_str());
- lo_message_add_string(m, node_path.c_str());
- lo_message_add_int32(m, is_polyphonic ? 1 : 0);
- lo_message_add_int32(m, num_ports);
-
- lo_bundle_add_message(b, "/om/new_node", m);
- msgs.push_back(m);
-*/
-
-
- /*
- const Array& ports = node->ports();
- Port* port;
- PortInfo* info;
- for (size_t j=0; j < ports.size(); ++j) {
- port = ports.at(j);
- info = port->port_info();
-
- assert(port != NULL);
- assert(info != NULL);
-
- m = lo_message_new();
- lo_message_add_string(m, port->path().c_str());
- lo_message_add_string(m, info->type_string().c_str());
- lo_message_add_string(m, info->direction_string().c_str());
- lo_message_add_string(m, info->hint_string().c_str());
- lo_message_add_float(m, info->default_val());
- lo_message_add_float(m, info->min_val());
- lo_message_add_float(m, info->max_val());
- lo_bundle_add_message(b, "/om/new_port", m);
- msgs.push_back(m);
-
- // If the bundle is getting very large, send it and start
- // a new one
- if (lo_bundle_length(b) > 1024) {
- lo_send_bundle(_address, b);
- lo_bundle_free(b);
- b = lo_bundle_new(tt);
- }
- }
-*/
- /*m = lo_message_new();
- //lo_bundle_add_message(b, "/om/new_node_end", m);
- //msgs.push_back(m);
-
- lo_send_bundle(_address, b);
- lo_bundle_free(b);
-
- for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
- lo_message_free(*i);
-
- usleep(100);
-*/
- /*
- const map& data = node->metadata();
- // Send node metadata
- for (map::const_iterator i = data.begin(); i != data.end(); ++i)
- metadata_update(node->path(), (*i).first, (*i).second);
-
-
- // Send port metadata
- for (size_t j=0; j < ports.size(); ++j) {
- port = ports.at(j);
- const map& data = port->metadata();
- for (map::const_iterator i = data.begin(); i != data.end(); ++i)
- metadata_update(port->path(), (*i).first, (*i).second);
- }
-
- // Send control values
- for (size_t i=0; i < node->ports().size(); ++i) {
- TypedPort* port = (TypedPort*)node->ports().at(i);
- if (port->port_info()->is_input() && port->port_info()->is_control())
- control_change(port->path(), port->buffer(0)->value_at(0));
- }
- */
-#endif
-}
-
-
-
-/** \page client_osc_namespace
- * \b /om/new_port - Notification of a new port's creation.
- * \arg \b path (string) - Path of new port
- * \arg \b data-type (string) - Type of port (CONTROL or AUDIO)
- * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1)
- *
- * \li Note that in the event of loading a patch, this message could be
- * followed immediately by a control change, meaning the default-value is
- * not actually the current value of the port.
- * \li The minimum and maximum values are suggestions only, they are not
- * enforced in any way, and going outside them is perfectly fine. Also note
- * that the port ranges in om_gtk are not these ones! Those ranges are set
- * as metadata.
\n \n
- */
-void
-OSCClient::new_port(const string& path,
- const string& data_type,
- bool is_output)
-{
- //PortInfo* info = port->port_info();
-
- lo_send(_address, "/om/new_port", "ssi", path.c_str(), data_type.c_str(), is_output);
-
- // Send metadata
- /*const map& data = port->metadata();
- for (map::const_iterator i = data.begin(); i != data.end(); ++i)
- metadata_update(port->path(), (*i).first, (*i).second);*/
-}
-
-
-/** \page client_osc_namespace
- * \b /om/destroyed - Notification an object has been destroyed
- * \arg \b path (string) - Path of object (which no longer exists)
\n \n
- */
-void
-OSCClient::object_destroyed(const string& path)
-{
- assert(path != "/");
-
- lo_send(_address, "/om/destroyed", "s", path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/patch_cleared - Notification a patch has been cleared (all children destroyed)
- * \arg \b path (string) - Path of patch (which is now empty)
\n \n
- */
-void
-OSCClient::patch_cleared(const string& patch_path)
-{
- lo_send(_address, "/om/patch_cleared", "s", patch_path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/patch_enabled - Notification a patch's DSP processing has been enabled.
- * \arg \b path (string) - Path of enabled patch
\n \n
- */
-void
-OSCClient::patch_enabled(const string& patch_path)
-{
- lo_send(_address, "/om/patch_enabled", "s", patch_path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/patch_disabled - Notification a patch's DSP processing has been disabled.
- * \arg \b path (string) - Path of disabled patch
\n \n
- */
-void
-OSCClient::patch_disabled(const string& patch_path)
-{
- lo_send(_address, "/om/patch_disabled", "s", patch_path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/new_connection - Notification a new connection has been made.
- * \arg \b src-path (string) - Path of the source port
- * \arg \b dst-path (string) - Path of the destination port
\n \n
- */
-void
-OSCClient::connection(const string& src_port_path, const string& dst_port_path)
-{
- lo_send(_address, "/om/new_connection", "ss", src_port_path.c_str(), dst_port_path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/disconnection - Notification a connection has been unmade.
- * \arg \b src-path (string) - Path of the source port
- * \arg \b dst-path (string) - Path of the destination port
\n \n
- */
-void
-OSCClient::disconnection(const string& src_port_path, const string& dst_port_path)
-{
- lo_send(_address, "/om/disconnection", "ss", src_port_path.c_str(), dst_port_path.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/metadata/update - Notification of a piece of metadata.
- * \arg \b path (string) - Path of the object associated with metadata (can be a node, patch, or port)
- * \arg \b key (string)
- * \arg \b value (string)
\n \n
- */
-void
-OSCClient::metadata_update(const string& path, const string& key, const string& value)
-{
- lo_send(_address, "/om/metadata/update", "sss", path.c_str(), key.c_str(), value.c_str());
-}
-
-
-/** \page client_osc_namespace
- * \b /om/control_change - Notification the value of a port has changed
- * \arg \b path (string) - Path of port
- * \arg \b value (float) - New value of port
- *
- * \li This will only send updates for values set by clients of course - not values
- * changing because of connections to other ports!
\n \n
- */
-void
-OSCClient::control_change(const string& port_path, float value)
-{
- lo_send(_address, "/om/control_change", "sf", port_path.c_str(), value);
-}
-
-
-/** \page client_osc_namespace
- * \b /om/plugin - Notification of the existance of a plugin
- * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")
\n \n
- * \arg \b uri (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")
\n \n
- * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope")
- */
-void
-OSCClient::new_plugin(const string& type, const string& uri, const string& name)
-{
- lo_message m = lo_message_new();
- lo_message_add_string(m, type.c_str());
- lo_message_add_string(m, uri.c_str());
- lo_message_add_string(m, name.c_str());
- lo_send_message(_address, "/om/plugin", m);
-}
-
-
-/** \page client_osc_namespace
- * \b /om/new_patch - Notification of a new patch
- * \arg \b path (string) - Path of new patch
- * \arg \b poly (int) - Polyphony of new patch (\em not a boolean like new_node)
\n \n
- */
-void
-OSCClient::new_patch(const string& path, uint32_t poly)
-{
- lo_send(_address, "/om/new_patch", "si", path.c_str(), poly);
-
- /*
- if (p->process())
- patch_enabled(p->path());
-
- // Send metadata
- const map& data = p->metadata();
- for (map::const_iterator i = data.begin(); i != data.end(); ++i) {
- metadata_update(p->path(), (*i).first, (*i).second);
- }
- */
-}
-
-
-/** \page client_osc_namespace
- * \b /om/object_renamed - Notification of an object's renaming
- * \arg \b old-path (string) - Old path of object
- * \arg \b new-path (string) - New path of object
\n \n
- */
-void
-OSCClient::object_renamed(const string& old_path, const string& new_path)
-{
- lo_send(_address, "/om/object_renamed", "ss", old_path.c_str(), new_path.c_str());
-}
-
-
-/** Sends all GraphObjects known to the engine.
- */
-/*
-void
-OSCClient::all_objects()
-{
- for (Tree::iterator i = Engine::instance().object_store()->objects().begin();
- i != Engine::instance().object_store()->objects().end(); ++i)
- if ((*i)->as_node() != NULL && (*i)->parent() == NULL)
- (*i)->as_node()->send_creation_messages(this);
-}
-*/
-
-/** Sends information about a program associated with a DSSI plugin node.
- */
-void
-OSCClient::program_add(const string& node_path, uint32_t bank, uint32_t program, const string& name)
-{
- lo_send(_address, "/om/program_add", "siis",
- node_path.c_str(), bank, program, name.c_str());
-}
-
-
-void
-OSCClient::program_remove(const string& node_path, uint32_t bank, uint32_t program)
-{
- lo_send(_address, "/om/program_remove", "sii",
- node_path.c_str(), bank, program);
-}
-
-
-} // namespace Ingen
diff --git a/src/libs/engine/OSCClient.h b/src/libs/engine/OSCClient.h
deleted file mode 100644
index 423bb32f..00000000
--- a/src/libs/engine/OSCClient.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef OSCCLIENT_H
-#define OSCCLIENT_H
-
-#include
-#include
-#include
-#include
-#include
-#include "types.h"
-#include "interface/ClientInterface.h"
-
-using std::list; using std::string;
-using std::cerr;
-
-namespace Ingen {
-
-
-/** Implements ClientInterface for OSC clients (sends OSC messages).
- *
- * \ingroup engine
- */
-class OSCClient : public Shared::ClientInterface
-{
-public:
- OSCClient(const string& url)
- : _url(url),
- _address(lo_address_new_from_url(url.c_str()))
- {}
-
- virtual ~OSCClient()
- { lo_address_free(_address); }
-
- const string& url() const { return _url; }
- const lo_address address() const { return _address; }
-
- //void plugins(); // FIXME remove
-
-
-
- /* *** ClientInterface Implementation Below *** */
-
-
- //void client_registration(const string& url, int client_id);
-
- // need a liblo feature to make this possible :/
- void bundle_begin() {}
- void bundle_end() {}
-
- void num_plugins(uint32_t num);
-
- void error(const string& msg);
-
- virtual void new_plugin(const string& type,
- const string& uri,
- const string& name);
-
- virtual void new_patch(const string& path, uint32_t poly);
-
- virtual void new_node(const string& plugin_type,
- const string& plugin_uri,
- const string& node_path,
- bool is_polyphonic,
- uint32_t num_ports);
-
- virtual void new_port(const string& path,
- const string& data_type,
- bool is_output);
-
- virtual void patch_enabled(const string& path);
-
- virtual void patch_disabled(const string& path);
-
- virtual void patch_cleared(const string& path);
-
- virtual void object_destroyed(const string& path);
-
- virtual void object_renamed(const string& old_path,
- const string& new_path);
-
- virtual void connection(const string& src_port_path,
- const string& dst_port_path);
-
- virtual void disconnection(const string& src_port_path,
- const string& dst_port_path);
-
- virtual void metadata_update(const string& subject_path,
- const string& predicate,
- const string& value);
-
- virtual void control_change(const string& port_path,
- float value);
-
- virtual void program_add(const string& node_path,
- uint32_t bank,
- uint32_t program,
- const string& program_name);
-
- virtual void program_remove(const string& node_path,
- uint32_t bank,
- uint32_t program);
-
-private:
- // Prevent copies (undefined)
- OSCClient(const OSCClient&);
- OSCClient& operator=(const OSCClient&);
-
- string _url;
- lo_address _address;
-};
-
-
-} // namespace Ingen
-
-#endif // OSCCLIENT_H
-
diff --git a/src/libs/engine/OSCClientSender.cpp b/src/libs/engine/OSCClientSender.cpp
new file mode 100644
index 00000000..d6f56e74
--- /dev/null
+++ b/src/libs/engine/OSCClientSender.cpp
@@ -0,0 +1,487 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OSCClientSender.h"
+#include
+#include
+#include
+#include "ObjectStore.h"
+#include "NodeFactory.h"
+#include "util.h"
+#include "Patch.h"
+#include "Node.h"
+#include "Plugin.h"
+#include "TypedPort.h"
+#include "Connection.h"
+#include "AudioDriver.h"
+#include "interface/ClientInterface.h"
+#include "Responder.h"
+
+using std::cout; using std::cerr; using std::endl;
+
+namespace Ingen {
+
+
+/*! \page client_osc_namespace Client OSC Namespace Documentation
+ *
+ * These are all the messages sent from the engine to the client.
+ * Communication takes place over two distinct bands: control band and
+ * notification band.
+ * The control band is where clients send commands, and receive a simple
+ * response, either OK or an error.
+ * All notifications of engine state (ie new nodes) are sent over the
+ * notification band which is seperate from the control band. The
+ * reasoning behind this is that many clients may be connected at the same
+ * time - a client may receive notifications that are not a direct consequence
+ * of some message it sent.
+ * The notification band can be thought of as a stream of events representing
+ * the changing engine state. For example, It is possible for a client to send
+ * commands and receive aknowledgements, and not listen to the notification band
+ * at all; or (in the near future anyway) for a client to use UDP for the control
+ * band (for speed), and TCP for the notification band (for reliability and
+ * order guarantees).
+ * \n\n
+ */
+
+
+/* Documentation for namespace portion implemented in Responder.cpp */
+
+/** \page client_osc_namespace
+ * \n
+ * Notification Band
+ */
+
+/** \page client_osc_namespace
+ * \b /om/response/ok - Respond successfully to a user command
+ * \arg \b responder-id (int) - Responder ID this is a response to
+ *
\n \n
+ */
+
+/** \page client_osc_namespace
+ * \b /om/response/error - Respond negatively to a user command
+ * \arg \b responder-id (int) - Request ID this is a response to
+ * \arg \b message (string) - Error message (natural language text)
+ *
\n \n
+ */
+
+
+
+/** \page client_osc_namespace
+ * \n
+ * Notification Band
+ */
+
+/** \page client_osc_namespace
+ * \b /om/error - Notification that an error has occurred
+ * \arg \b message (string) - Error message (natural language text)
+ *
+ * \li This is for notification of errors that aren't a direct response to a
+ * user command, ie "unexpected" errors.
\n \n
+ */
+void
+OSCClientSender::error(const string& msg)
+{
+ lo_send(_address, "/om/error", "s", msg.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/num_plugins
+ * \arg \b num (int) - Number of plugins engine has loaded
+ * \li This is sent before sending the list of plugins, so the client is aware
+ * of how many plugins (/om/plugin messages) to expect.
\n \n
+ */
+
+
+/** \page client_osc_namespace
+ * \b /om/num_plugins
+ * \arg \b num (int) - Number of plugins engine has loaded
+ * \li This is sent before sending the list of plugins, so the client is aware
+ * of how many plugins (/om/plugin messages) to expect.
\n \n
+ */
+void
+OSCClientSender::num_plugins(uint32_t num)
+{
+ lo_message m = lo_message_new();
+ lo_message_add_int32(m, num);
+ lo_send_message(_address, "/om/num_plugins", m);
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/plugin - Notification of the existance of a plugin
+ * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")
+ * \arg \b uri (string) - URI of the plugin (see engine namespace documentation) \n
+ * \arg \b lib-name (string) - Name of shared library plugin resides in (ie "cmt.so")
+ * \arg \b plug-label (string) - Label of the plugin (ie "dahdsr_iaoa")
+ * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope")
+ *
\n \n
+ */
+/*
+void
+OSCClientSender::plugins()
+{
+ Engine::instance().node_factory()->lock_plugin_list();
+
+ const list& plugs = Engine::instance().node_factory()->plugins();
+ const Plugin* plugin;
+
+ lo_timetag tt;
+ lo_timetag_now(&tt);
+ lo_bundle b = lo_bundle_new(tt);
+ lo_message m = lo_message_new();
+ list msgs;
+
+ lo_message_add_int32(m, plugs.size());
+ lo_bundle_add_message(b, "/om/num_plugins", m);
+ msgs.push_back(m);
+
+ for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) {
+ plugin = (*j);
+ m = lo_message_new();
+
+ lo_message_add_string(m, plugin->type_string());
+ lo_message_add_string(m, plugin->uri().c_str());
+ lo_message_add_string(m, plugin->plug_label().c_str());
+ lo_message_add_string(m, plugin->name().c_str());
+ lo_bundle_add_message(b, "/om/plugin", m);
+ msgs.push_back(m);
+ if (lo_bundle_length(b) > 1024) {
+ lo_send_bundle(_address, b);
+ lo_bundle_free(b);
+ b = lo_bundle_new(tt);
+ }
+ }
+
+ if (lo_bundle_length(b) > 0) {
+ lo_send_bundle(_address, b);
+ lo_bundle_free(b);
+ } else {
+ lo_bundle_free(b);
+ }
+ for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
+ lo_message_free(*i);
+
+ Engine::instance().node_factory()->unlock_plugin_list();
+}
+*/
+
+/** \page client_osc_namespace
+ * \b /om/new_node - Notification of a new node's creation.
+ * \arg \b plug-uri (string) - URI of the plugin new node is an instance of
+ * \arg \b path (string) - Path of the new node
+ * \arg \b polyphonic (integer-boolean) - Node is polyphonic (1 = yes, 0 = no)
+ * \arg \b num-ports (integer) - Number of ports (number of new_port messages to expect)
+ * \li New nodes are sent as a bundle. The first message in the bundle will be
+ * this one (/om/new_node), followed by a series of /om/new_port commands,
+ * followed by /om/new_node_end.
\n \n
+ */
+void OSCClientSender::new_node(const string& plugin_type,
+ const string& plugin_uri,
+ const string& node_path,
+ bool is_polyphonic,
+ uint32_t num_ports)
+{
+ lo_send(_address, "/om/new_node", "sssii", plugin_type.c_str(), plugin_uri.c_str(),
+ node_path.c_str(), is_polyphonic ? 1 : 0, num_ports);
+#if 0
+ /*
+ lo_timetag tt;
+ lo_timetag_now(&tt);
+ lo_bundle b = lo_bundle_new(tt);
+ lo_message m = lo_message_new();
+ list msgs;
+
+ lo_message_add_string(m, plugin_type.c_str());
+ lo_message_add_string(m, plugin_uri.c_str());
+ lo_message_add_string(m, node_path.c_str());
+ lo_message_add_int32(m, is_polyphonic ? 1 : 0);
+ lo_message_add_int32(m, num_ports);
+
+ lo_bundle_add_message(b, "/om/new_node", m);
+ msgs.push_back(m);
+*/
+
+
+ /*
+ const Array& ports = node->ports();
+ Port* port;
+ PortInfo* info;
+ for (size_t j=0; j < ports.size(); ++j) {
+ port = ports.at(j);
+ info = port->port_info();
+
+ assert(port != NULL);
+ assert(info != NULL);
+
+ m = lo_message_new();
+ lo_message_add_string(m, port->path().c_str());
+ lo_message_add_string(m, info->type_string().c_str());
+ lo_message_add_string(m, info->direction_string().c_str());
+ lo_message_add_string(m, info->hint_string().c_str());
+ lo_message_add_float(m, info->default_val());
+ lo_message_add_float(m, info->min_val());
+ lo_message_add_float(m, info->max_val());
+ lo_bundle_add_message(b, "/om/new_port", m);
+ msgs.push_back(m);
+
+ // If the bundle is getting very large, send it and start
+ // a new one
+ if (lo_bundle_length(b) > 1024) {
+ lo_send_bundle(_address, b);
+ lo_bundle_free(b);
+ b = lo_bundle_new(tt);
+ }
+ }
+*/
+ /*m = lo_message_new();
+ //lo_bundle_add_message(b, "/om/new_node_end", m);
+ //msgs.push_back(m);
+
+ lo_send_bundle(_address, b);
+ lo_bundle_free(b);
+
+ for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
+ lo_message_free(*i);
+
+ usleep(100);
+*/
+ /*
+ const map& data = node->metadata();
+ // Send node metadata
+ for (map::const_iterator i = data.begin(); i != data.end(); ++i)
+ metadata_update(node->path(), (*i).first, (*i).second);
+
+
+ // Send port metadata
+ for (size_t j=0; j < ports.size(); ++j) {
+ port = ports.at(j);
+ const map& data = port->metadata();
+ for (map::const_iterator i = data.begin(); i != data.end(); ++i)
+ metadata_update(port->path(), (*i).first, (*i).second);
+ }
+
+ // Send control values
+ for (size_t i=0; i < node->ports().size(); ++i) {
+ TypedPort* port = (TypedPort*)node->ports().at(i);
+ if (port->port_info()->is_input() && port->port_info()->is_control())
+ control_change(port->path(), port->buffer(0)->value_at(0));
+ }
+ */
+#endif
+}
+
+
+
+/** \page client_osc_namespace
+ * \b /om/new_port - Notification of a new port's creation.
+ * \arg \b path (string) - Path of new port
+ * \arg \b data-type (string) - Type of port (CONTROL or AUDIO)
+ * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1)
+ *
+ * \li Note that in the event of loading a patch, this message could be
+ * followed immediately by a control change, meaning the default-value is
+ * not actually the current value of the port.
+ * \li The minimum and maximum values are suggestions only, they are not
+ * enforced in any way, and going outside them is perfectly fine. Also note
+ * that the port ranges in om_gtk are not these ones! Those ranges are set
+ * as metadata.
\n \n
+ */
+void
+OSCClientSender::new_port(const string& path,
+ const string& data_type,
+ bool is_output)
+{
+ //PortInfo* info = port->port_info();
+
+ lo_send(_address, "/om/new_port", "ssi", path.c_str(), data_type.c_str(), is_output);
+
+ // Send metadata
+ /*const map& data = port->metadata();
+ for (map::const_iterator i = data.begin(); i != data.end(); ++i)
+ metadata_update(port->path(), (*i).first, (*i).second);*/
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/destroyed - Notification an object has been destroyed
+ * \arg \b path (string) - Path of object (which no longer exists)
\n \n
+ */
+void
+OSCClientSender::object_destroyed(const string& path)
+{
+ assert(path != "/");
+
+ lo_send(_address, "/om/destroyed", "s", path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/patch_cleared - Notification a patch has been cleared (all children destroyed)
+ * \arg \b path (string) - Path of patch (which is now empty)
\n \n
+ */
+void
+OSCClientSender::patch_cleared(const string& patch_path)
+{
+ lo_send(_address, "/om/patch_cleared", "s", patch_path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/patch_enabled - Notification a patch's DSP processing has been enabled.
+ * \arg \b path (string) - Path of enabled patch
\n \n
+ */
+void
+OSCClientSender::patch_enabled(const string& patch_path)
+{
+ lo_send(_address, "/om/patch_enabled", "s", patch_path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/patch_disabled - Notification a patch's DSP processing has been disabled.
+ * \arg \b path (string) - Path of disabled patch
\n \n
+ */
+void
+OSCClientSender::patch_disabled(const string& patch_path)
+{
+ lo_send(_address, "/om/patch_disabled", "s", patch_path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/new_connection - Notification a new connection has been made.
+ * \arg \b src-path (string) - Path of the source port
+ * \arg \b dst-path (string) - Path of the destination port
\n \n
+ */
+void
+OSCClientSender::connection(const string& src_port_path, const string& dst_port_path)
+{
+ lo_send(_address, "/om/new_connection", "ss", src_port_path.c_str(), dst_port_path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/disconnection - Notification a connection has been unmade.
+ * \arg \b src-path (string) - Path of the source port
+ * \arg \b dst-path (string) - Path of the destination port
\n \n
+ */
+void
+OSCClientSender::disconnection(const string& src_port_path, const string& dst_port_path)
+{
+ lo_send(_address, "/om/disconnection", "ss", src_port_path.c_str(), dst_port_path.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/metadata/update - Notification of a piece of metadata.
+ * \arg \b path (string) - Path of the object associated with metadata (can be a node, patch, or port)
+ * \arg \b key (string)
+ * \arg \b value (string)
\n \n
+ */
+void
+OSCClientSender::metadata_update(const string& path, const string& key, const string& value)
+{
+ lo_send(_address, "/om/metadata/update", "sss", path.c_str(), key.c_str(), value.c_str());
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/control_change - Notification the value of a port has changed
+ * \arg \b path (string) - Path of port
+ * \arg \b value (float) - New value of port
+ *
+ * \li This will only send updates for values set by clients of course - not values
+ * changing because of connections to other ports!
\n \n
+ */
+void
+OSCClientSender::control_change(const string& port_path, float value)
+{
+ lo_send(_address, "/om/control_change", "sf", port_path.c_str(), value);
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/plugin - Notification of the existance of a plugin
+ * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")
\n \n
+ * \arg \b uri (string) - Type if plugin ("LADSPA", "DSSI", or "Internal") \n \n
+ * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope")
+ */
+void
+OSCClientSender::new_plugin(const string& type, const string& uri, const string& name)
+{
+ lo_message m = lo_message_new();
+ lo_message_add_string(m, type.c_str());
+ lo_message_add_string(m, uri.c_str());
+ lo_message_add_string(m, name.c_str());
+ lo_send_message(_address, "/om/plugin", m);
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/new_patch - Notification of a new patch
+ * \arg \b path (string) - Path of new patch
+ * \arg \b poly (int) - Polyphony of new patch (\em not a boolean like new_node)
\n \n
+ */
+void
+OSCClientSender::new_patch(const string& path, uint32_t poly)
+{
+ lo_send(_address, "/om/new_patch", "si", path.c_str(), poly);
+
+ /*
+ if (p->process())
+ patch_enabled(p->path());
+
+ // Send metadata
+ const map& data = p->metadata();
+ for (map::const_iterator i = data.begin(); i != data.end(); ++i) {
+ metadata_update(p->path(), (*i).first, (*i).second);
+ }
+ */
+}
+
+
+/** \page client_osc_namespace
+ * \b /om/object_renamed - Notification of an object's renaming
+ * \arg \b old-path (string) - Old path of object
+ * \arg \b new-path (string) - New path of object
\n \n
+ */
+void
+OSCClientSender::object_renamed(const string& old_path, const string& new_path)
+{
+ lo_send(_address, "/om/object_renamed", "ss", old_path.c_str(), new_path.c_str());
+}
+
+
+/** Sends information about a program associated with a DSSI plugin node.
+ */
+void
+OSCClientSender::program_add(const string& node_path, uint32_t bank, uint32_t program, const string& name)
+{
+ lo_send(_address, "/om/program_add", "siis",
+ node_path.c_str(), bank, program, name.c_str());
+}
+
+
+void
+OSCClientSender::program_remove(const string& node_path, uint32_t bank, uint32_t program)
+{
+ lo_send(_address, "/om/program_remove", "sii",
+ node_path.c_str(), bank, program);
+}
+
+
+} // namespace Ingen
diff --git a/src/libs/engine/OSCClientSender.h b/src/libs/engine/OSCClientSender.h
new file mode 100644
index 00000000..1826a36d
--- /dev/null
+++ b/src/libs/engine/OSCClientSender.h
@@ -0,0 +1,131 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OSCCLIENTSENDER_H
+#define OSCCLIENTSENDER_H
+
+#include
+#include
+#include
+#include
+#include
+#include "types.h"
+#include "interface/ClientInterface.h"
+
+using std::list; using std::string;
+using std::cerr;
+
+namespace Ingen {
+
+
+/** Implements ClientInterface for OSC clients (sends OSC messages).
+ *
+ * \ingroup engine
+ */
+class OSCClientSender : public Shared::ClientInterface
+{
+public:
+ OSCClientSender(const string& url)
+ : _url(url),
+ _address(lo_address_new_from_url(url.c_str()))
+ {}
+
+ virtual ~OSCClientSender()
+ { lo_address_free(_address); }
+
+ const string& url() const { return _url; }
+ const lo_address address() const { return _address; }
+
+ //void plugins(); // FIXME remove
+
+
+
+ /* *** ClientInterface Implementation Below *** */
+
+
+ //void client_registration(const string& url, int client_id);
+
+ // need a liblo feature to make this possible :/
+ void bundle_begin() {}
+ void bundle_end() {}
+
+ void num_plugins(uint32_t num);
+
+ void error(const string& msg);
+
+ virtual void new_plugin(const string& type,
+ const string& uri,
+ const string& name);
+
+ virtual void new_patch(const string& path, uint32_t poly);
+
+ virtual void new_node(const string& plugin_type,
+ const string& plugin_uri,
+ const string& node_path,
+ bool is_polyphonic,
+ uint32_t num_ports);
+
+ virtual void new_port(const string& path,
+ const string& data_type,
+ bool is_output);
+
+ virtual void patch_enabled(const string& path);
+
+ virtual void patch_disabled(const string& path);
+
+ virtual void patch_cleared(const string& path);
+
+ virtual void object_destroyed(const string& path);
+
+ virtual void object_renamed(const string& old_path,
+ const string& new_path);
+
+ virtual void connection(const string& src_port_path,
+ const string& dst_port_path);
+
+ virtual void disconnection(const string& src_port_path,
+ const string& dst_port_path);
+
+ virtual void metadata_update(const string& subject_path,
+ const string& predicate,
+ const string& value);
+
+ virtual void control_change(const string& port_path,
+ float value);
+
+ virtual void program_add(const string& node_path,
+ uint32_t bank,
+ uint32_t program,
+ const string& program_name);
+
+ virtual void program_remove(const string& node_path,
+ uint32_t bank,
+ uint32_t program);
+
+private:
+ // Prevent copies (undefined)
+ OSCClientSender(const OSCClientSender&);
+ OSCClientSender& operator=(const OSCClientSender&);
+
+ string _url;
+ lo_address _address;
+};
+
+
+} // namespace Ingen
+
+#endif // OSCCLIENTSENDER_H
+
diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp
new file mode 100644
index 00000000..4b1ae496
--- /dev/null
+++ b/src/libs/engine/OSCEngineReceiver.cpp
@@ -0,0 +1,909 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OSCEngineReceiver.h"
+#include
+#include
+#include
+#include
+#include "types.h"
+#include "util/Queue.h"
+#include "util/CountedPtr.h"
+#include "QueuedEventSource.h"
+#include "interface/ClientKey.h"
+#include "interface/ClientInterface.h"
+#include "OSCClientSender.h"
+#include "OSCResponder.h"
+#include "ClientBroadcaster.h"
+
+using std::cerr; using std::cout; using std::endl;
+
+namespace Ingen {
+
+using Shared::ClientKey;
+
+
+/*! \page engine_osc_namespace Engine OSC Namespace Documentation
+ *
+ * These are the commands the engine recognizes. A client can control every
+ * aspect of the engine entirely with these commands.
+ *
+ * All commands on this page are in the "control band". If a client needs to
+ * know about the state of the engine, it must listen to the "notification band".
+ * See the "Client OSC Namespace Documentation" for details.
+ */
+
+
+OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, const char* const port)
+: QueuedEngineInterface(engine, queue_size, queue_size), // FIXME
+ _port(port),
+ _server(NULL),
+ _osc_responder(NULL)
+{
+ _server = lo_server_new(port, error_cb);
+
+ if (_server == NULL) {
+ cerr << "[OSC] Could not start OSC server. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ } else {
+ char* lo_url = lo_server_get_url(_server);
+ cout << "[OSC] Started OSC server at " << lo_url << endl;
+ free(lo_url);
+ }
+
+ // For debugging, print all incoming OSC messages
+ lo_server_add_method(_server, NULL, NULL, generic_cb, NULL);
+
+ // Set response address for this message.
+ // It's important this is first and returns nonzero.
+ lo_server_add_method(_server, NULL, NULL, set_response_address_cb, this);
+
+ // Commands
+ lo_server_add_method(_server, "/om/ping", "i", ping_cb, this);
+ lo_server_add_method(_server, "/om/ping_slow", "i", ping_slow_cb, this);
+ lo_server_add_method(_server, "/om/engine/quit", "i", quit_cb, this);
+ //lo_server_add_method(_server, "/om/engine/register_client", "is", register_client_cb, this);
+ lo_server_add_method(_server, "/om/engine/register_client", "i", register_client_cb, this);
+ lo_server_add_method(_server, "/om/engine/unregister_client", "i", unregister_client_cb, this);
+ lo_server_add_method(_server, "/om/engine/load_plugins", "i", load_plugins_cb, this);
+ lo_server_add_method(_server, "/om/engine/activate", "i", engine_activate_cb, this);
+ lo_server_add_method(_server, "/om/engine/deactivate", "i", engine_deactivate_cb, this);
+ lo_server_add_method(_server, "/om/synth/create_patch", "isi", create_patch_cb, this);
+ lo_server_add_method(_server, "/om/synth/enable_patch", "is", enable_patch_cb, this);
+ lo_server_add_method(_server, "/om/synth/disable_patch", "is", disable_patch_cb, this);
+ lo_server_add_method(_server, "/om/synth/clear_patch", "is", clear_patch_cb, this);
+ lo_server_add_method(_server, "/om/synth/create_port", "issi", create_port_cb, this);
+ lo_server_add_method(_server, "/om/synth/create_node", "issssi", create_node_cb, this);
+ lo_server_add_method(_server, "/om/synth/create_node", "isssi", create_node_by_uri_cb, this);
+ lo_server_add_method(_server, "/om/synth/destroy", "is", destroy_cb, this);
+ lo_server_add_method(_server, "/om/synth/rename", "iss", rename_cb, this);
+ lo_server_add_method(_server, "/om/synth/connect", "iss", connect_cb, this);
+ lo_server_add_method(_server, "/om/synth/disconnect", "iss", disconnect_cb, this);
+ lo_server_add_method(_server, "/om/synth/disconnect_all", "is", disconnect_all_cb, this);
+ lo_server_add_method(_server, "/om/synth/set_port_value", "isf", set_port_value_cb, this);
+ lo_server_add_method(_server, "/om/synth/set_port_value", "isif", set_port_value_voice_cb, this);
+ lo_server_add_method(_server, "/om/synth/set_port_value_slow", "isf", set_port_value_slow_cb, this);
+ lo_server_add_method(_server, "/om/synth/note_on", "isii", note_on_cb, this);
+ lo_server_add_method(_server, "/om/synth/note_off", "isi", note_off_cb, this);
+ lo_server_add_method(_server, "/om/synth/all_notes_off", "isi", all_notes_off_cb, this);
+ lo_server_add_method(_server, "/om/synth/midi_learn", "is", midi_learn_cb, this);
+#ifdef HAVE_LASH
+ lo_server_add_method(_server, "/om/lash/restore_finished", "i", lash_restore_done_cb, this);
+#endif
+
+ lo_server_add_method(_server, "/om/metadata/request", "isss", metadata_get_cb, this);
+ lo_server_add_method(_server, "/om/metadata/set", "isss", metadata_set_cb, this);
+
+ // Queries
+ lo_server_add_method(_server, "/om/request/plugins", "i", request_plugins_cb, this);
+ lo_server_add_method(_server, "/om/request/all_objects", "i", request_all_objects_cb, this);
+ lo_server_add_method(_server, "/om/request/port_value", "is", request_port_value_cb, this);
+
+ // DSSI support
+#ifdef HAVE_DSSI
+ // XXX WARNING: notice this is a catch-all
+ lo_server_add_method(_server, NULL, NULL, dssi_cb, this);
+#endif
+
+ lo_server_add_method(_server, NULL, NULL, unknown_cb, NULL);
+}
+
+
+OSCEngineReceiver::~OSCEngineReceiver()
+{
+ deactivate();
+
+ if (_server != NULL) {
+ lo_server_free(_server);
+ _server = NULL;
+ }
+}
+
+
+void
+OSCEngineReceiver::activate()
+{
+ set_name("OSCEngineReceiver");
+ QueuedEventSource::activate();
+ set_scheduling(SCHED_FIFO, 10);
+}
+
+
+void
+OSCEngineReceiver::deactivate()
+{
+ cout << "[OSCEngineReceiver] Stopped OSC listening thread" << endl;
+ QueuedEventSource::deactivate();
+}
+
+
+/** Override the semaphore driven _run method of QueuedEngineInterface
+ * to wait on OSC messages and prepare them right away in the same thread.
+ */
+void
+OSCEngineReceiver::_run()
+{
+ /* get a timestamp here and stamp all the events with the same time so
+ * they all get executed in the same cycle */
+
+ while (true) {
+ assert( ! unprepared_events());
+
+ // Wait on a message and enqueue it
+ lo_server_recv(_server);
+
+ // Enqueue every other message that is here "now"
+ // (would this provide truly atomic bundles?)
+ while (lo_server_recv_noblock(_server, 0) > 0) ;
+
+ // Process them all
+ while (unprepared_events())
+ _whipped(); // Whip our slave self
+
+ // No more unprepared events
+ }
+}
+
+
+/** Create a new responder for this message, if necessary.
+ *
+ * This is based on the fact that the current responder is stored in a ref
+ * counted pointer, and events just take a reference to that. Thus, events
+ * may delete their responder if we've since switched to a new one, or the
+ * same one can stay around and serve a series of events. Reference counting
+ * is pretty sweet, eh?
+ *
+ * If this message came from the same source as the last message, no allocation
+ * of responders or lo_addresses or any of it needs to be done. Unfortunately
+ * the only way to check is by comparing URLs, because liblo addresses suck.
+ *
+ * Really, this entire thing is a basically just a crafty way of partially
+ * working around the fact that liblo addresses really suck. Oh well.
+ */
+int
+OSCEngineReceiver::set_response_address_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
+{
+ OSCEngineReceiver* const me = reinterpret_cast(user_data);
+
+ //cerr << "SET RESPONSE\n";
+
+ if (argc < 1 || types[0] != 'i') // Not a valid Ingen message
+ return 0; // Save liblo the trouble
+
+ //cerr << "** valid msg\n";
+
+ const int id = argv[0]->i;
+
+ // Need to respond
+ if (id != -1) {
+ const lo_address addr = lo_message_get_source(msg);
+ char* const url = lo_address_get_url(addr);
+
+ //cerr << "** need to respond\n";
+
+ // Currently have an OSC responder, check if it's still okay
+ if (me->_responder == me->_osc_responder) {
+ //cerr << "** osc responder\n";
+
+ if (!strcmp(url, me->_osc_responder->url())) {
+ // Nice one, same address
+ //cerr << "** Using cached response address, hooray" << endl;
+ } else {
+ // Shitty deal, make a new one
+ //cerr << "** Setting response address to " << url << "(2)" << endl;
+ me->_osc_responder = CountedPtr(new OSCResponder(id, url));
+ me->set_responder(me->_osc_responder);
+ // (responder takes ownership of url, no leak)
+ }
+
+ // Otherwise we have a NULL responder, definitely need to set a new one
+ } else {
+ //cerr << "** null responder\n";
+ me->_osc_responder = CountedPtr(new OSCResponder(id, url));
+ me->set_responder(me->_osc_responder);
+ //cerr << "** Setting response address to " << url << "(2)" << endl;
+ }
+
+ // Don't respond
+ } else {
+ me->disable_responses();
+ //cerr << "** Not responding." << endl;
+ }
+
+ // If this returns 0 no OSC commands will work
+ return 1;
+}
+
+
+void
+OSCEngineReceiver::error_cb(int num, const char* msg, const char* path)
+{
+ cerr << "liblo server error " << num << " in path \"" << "\" - " << msg << endl;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/ping - Immediately sends a successful response to the given response id.
+ * \arg \b response-id (integer)
\n \n
+ */
+int
+OSCEngineReceiver::m_ping_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ _responder->respond_ok();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/ping_slow - Sends response after going through the ("slow") event queue.
+ * \arg \b response-id (integer)
+ *
+ * \li See the documentation for /om/synth/set_port_value_slow for an explanation of how
+ * this differs from /om/ping. This is useful to send after sending a large cluster of
+ * events as a sentinel and wait on it's response, to know when the events are all
+ * finished processing.
\n \n
+ */
+int
+OSCEngineReceiver::m_ping_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ ping();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/engine/quit - Terminates the engine.
+ * \arg \b response-id (integer)
+ *
+ * \li Note that there is NO order guarantees with this command at all. You could
+ * send 10 messages then quit, and the quit reply could come immediately and the
+ * 10 messages would never get executed.
\n \n
+ */
+int
+OSCEngineReceiver::m_quit_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+
+ quit();
+ return 0;
+}
+
+/** \page engine_osc_namespace
+ * \b /om/engine/register_client - Registers a new client with the engine
+ * \arg \b response-id (integer)
+ *
+ * The incoming address will be used for the new registered client. If you
+ * want to register a different specific address, use the URL version.
+ */
+int
+OSCEngineReceiver::m_register_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ lo_address addr = lo_message_get_source(msg);
+
+ char* const url = lo_address_get_url(addr);
+ CountedPtr client(new OSCClientSender((const char*)url));
+ register_client(ClientKey(ClientKey::OSC_URL, (const char*)url), client);
+ free(url);
+
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/engine/unregister_client - Unregisters a client
+ * \arg \b response-id (integer)
\n \n
+ */
+int
+OSCEngineReceiver::m_unregister_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ lo_address addr = lo_message_get_source(msg);
+
+ char* url = lo_address_get_url(addr);
+ unregister_client(ClientKey(ClientKey::OSC_URL, url));
+ free(url);
+
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/engine/load_plugins - Locates all available plugins, making them available for use.
+ * \arg \b response-id (integer)
\n \n
+ */
+int
+OSCEngineReceiver::m_load_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ load_plugins();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/engine/activate - Activate the engine (MIDI, audio, everything)
+ * \arg \b response-id (integer)
+ *
+ * \li Note that you must send this message first if you want the engine to do
+ * anything at all - including respond to your messages! \n \n
+ */
+int
+OSCEngineReceiver::m_engine_activate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ QueuedEngineInterface::activate();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/engine/deactivate - Deactivate the engine completely.
+ * \arg \b response-id (integer)
\n \n
+ */
+int
+OSCEngineReceiver::m_engine_deactivate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ QueuedEngineInterface::deactivate();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/create_patch - Creates a new, empty, toplevel patch.
+ * \arg \b response-id (integer)
+ * \arg \b patch-path (string) - Patch path (complete, ie /master/parent/new_patch)
+ * \arg \b poly (integer) - Patch's (internal) polyphony
\n \n
+ */
+int
+OSCEngineReceiver::m_create_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* patch_path = &argv[1]->s;
+ const int poly = argv[2]->i;
+
+ create_patch(patch_path, poly);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/rename - Rename an Object (only Nodes, for now)
+ * \arg \b response-id (integer)
+ * \arg \b path - Object's path
+ * \arg \b name - New name for object
\n \n
+ */
+int
+OSCEngineReceiver::m_rename_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* object_path = &argv[1]->s;
+ const char* name = &argv[2]->s;
+
+ rename(object_path, name);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/enable_patch - Enable DSP processing of a patch
+ * \arg \b response-id (integer)
+ * \arg \b patch-path - Patch's path
+ */
+int
+OSCEngineReceiver::m_enable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* patch_path = &argv[1]->s;
+
+ enable_patch(patch_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/synth/disable_patch - Disable DSP processing of a patch
+ * \arg \b response-id (integer)
+ * \arg \b patch-path - Patch's path
+ */
+int
+OSCEngineReceiver::m_disable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* patch_path = &argv[1]->s;
+
+ disable_patch(patch_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/synth/clear_patch - Remove all nodes from a patch
+ * \arg \b response-id (integer)
+ * \arg \b patch-path - Patch's path
+ */
+int
+OSCEngineReceiver::m_clear_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* patch_path = &argv[1]->s;
+
+ clear_patch(patch_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/synth/create_port - Add a port into a given patch (load a plugin by URI)
+ * \arg \b response-id (integer)
+ * \arg \b path (string) - Full path of the new port (ie. /patch2/subpatch/newport)
+ * \arg \b data-type (string) - Data type for port to contain ("AUDIO", "CONTROL", or "MIDI")
+ * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1)
\n \n
+ */
+int
+OSCEngineReceiver::m_create_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[1]->s;
+ const char* data_type = &argv[2]->s;
+ const int direction = argv[3]->i;
+
+ create_port(port_path, data_type, (direction == 1));
+ return 0;
+}
+
+/** \page engine_osc_namespace
+ * \b /om/synth/create_node - Add a node into a given patch (load a plugin by URI)
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode)
+ * \arg \b type (string) - Plugin type ("Internal", "LV2", "DSSI", "LADSPA")
+ * \arg \b plug-uri (string) - URI of the plugin to load
+ * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)
\n \n
+ */
+int
+OSCEngineReceiver::m_create_node_by_uri_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[1]->s;
+ const char* type = &argv[2]->s;
+ const char* plug_uri = &argv[3]->s;
+ const int poly = argv[4]->i;
+
+ // FIXME: make sure poly is valid
+
+ create_node(node_path, type, plug_uri, (poly == 1));
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/create_node - Add a node into a given patch (load a plugin by libname, label) \b DEPRECATED
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode)
+ * \arg \b type (string) - Plugin type ("LADSPA" or "Internal")
+ * \arg \b lib-name (string) - Name of library where plugin resides (eg "cmt.so")
+ * \arg \b plug-label (string) - Label (ID) of plugin (eg "sine_fcaa")
+ * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)
+ *
+ * \li This is only here to provide backwards compatibility for old patches that store LADSPA plugin
+ * references as libname, label. It is to be removed ASAP, don't use it.
+ *
\n \n
+ */
+int
+OSCEngineReceiver::m_create_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[1]->s;
+ const char* type = &argv[2]->s;
+ const char* lib_name = &argv[3]->s;
+ const char* plug_label = &argv[4]->s;
+ const int poly = argv[5]->i;
+
+ create_node(node_path, type, lib_name, plug_label, (poly == 1));
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/destroy - Removes (destroys) a Patch or a Node
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Full path of the object
\n \n
+ */
+int
+OSCEngineReceiver::m_destroy_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[1]->s;
+
+ destroy(node_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/connect - Connects two ports (must be in the same patch)
+ * \arg \b response-id (integer)
+ * \arg \b src-port-path (string) - Full path of source port
+ * \arg \b dst-port-path (string) - Full path of destination port
\n \n
+ */
+int
+OSCEngineReceiver::m_connect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* src_port_path = &argv[1]->s;
+ const char* dst_port_path = &argv[2]->s;
+
+ connect(src_port_path, dst_port_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/disconnect - Disconnects two ports.
+ * \arg \b response-id (integer)
+ * \arg \b src-port-path (string) - Full path of source port
+ * \arg \b dst-port-path (string) - Full path of destination port
\n \n
+ */
+int
+OSCEngineReceiver::m_disconnect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* src_port_path = &argv[1]->s;
+ const char* dst_port_path = &argv[2]->s;
+
+ disconnect(src_port_path, dst_port_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/disconnect_all - Disconnect all connections to/from a node.
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Full path of node.
\n \n
+ */
+int
+OSCEngineReceiver::m_disconnect_all_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[1]->s;
+
+ disconnect_all(node_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/set_port_value - Sets the value of a port for all voices (both AR and CR)
+ * \arg \b response-id (integer)
+ * \arg \b port-path (string) - Name of port
+ * \arg \b value (float) - Value to set port to
+ */
+int
+OSCEngineReceiver::m_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[1]->s;
+ const float value = argv[2]->f;
+
+ set_port_value(port_path, value);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/synth/set_port_value - Sets the value of a port for a specific voice (both AR and CR)
+ * \arg \b response-id (integer)
+ * \arg \b port-path (string) - Name of port
+ * \arg \b voice (integer) - Voice to set port value for
+ * \arg \b value (float) - Value to set port to
+ */
+int
+OSCEngineReceiver::m_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[1]->s;
+ const int voice = argv[2]->i;
+ const float value = argv[3]->f;
+
+ set_port_value(port_path, voice, value);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/synth/set_port_value_slow - Sets the value of a port for all voices (as a QueuedEvent)
+ * \arg \b response-id (integer)
+ * \arg \b port-path (string) - Name of port
+ * \arg \b value (float) - Value to set port to
+ *
+ * \li This version exists so you can send it immediately after a QueuedEvent it may depend on (ie a
+ * node creation) and be sure it happens after the event (a normal set_port_value could beat the
+ * slow event and arrive out of order).
\n \n
+ */
+int
+OSCEngineReceiver::m_set_port_value_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[1]->s;
+ const float value = argv[2]->f;
+
+ set_port_value_queued(port_path, value);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/note_on - Triggers a note-on, just as if it came from MIDI
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node)
+ * \arg \b note-num (int) - MIDI style note number (0-127)
+ * \arg \b velocity (int) - MIDI style velocity (0-127)
\n \n
+ */
+int
+OSCEngineReceiver::m_note_on_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ /*
+
+ const char* node_path = &argv[1]->s;
+ const uchar note_num = argv[2]->i;
+ const uchar velocity = argv[3]->i;
+ */
+ cerr << "FIXME: OSC note on\n";
+ //note_on(node_path, note_num, velocity);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/note_off - Triggers a note-off, just as if it came from MIDI
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node)
+ * \arg \b note-num (int) - MIDI style note number (0-127)
\n \n
+ */
+int
+OSCEngineReceiver::m_note_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ /*
+
+ const char* patch_path = &argv[1]->s;
+ const uchar note_num = argv[2]->i;
+ */
+ cerr << "FIXME: OSC note off\n";
+ //note_off(patch_path, note_num);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/all_notes_off - Triggers a note-off for all voices, just as if it came from MIDI
+ * \arg \b response-id (integer)
+ * \arg \b patch-path (string) - Patch of patch to send event to
\n \n
+ */
+int
+OSCEngineReceiver::m_all_notes_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ /*
+
+ const char* patch_path = &argv[1]->s;
+ */
+ cerr << "FIXME: OSC all notes off\n";
+ //all_notes_off(patch_path);
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/synth/midi_learn - Initiate MIDI learn for a given (MIDI Control) Node
+ * \arg \b response-id (integer)
+ * \arg \b node-path (string) - Patch of the Node that should learn the next MIDI event.
+ *
+ * \li This of course will only do anything for MIDI control nodes. The node will learn the next MIDI
+ * event that arrives at it's MIDI input port - no behind the scenes voodoo happens here. It is planned
+ * that a plugin specification supporting arbitrary OSC commands for plugins will exist one day, and this
+ * method will go away completely.
\n \n
+ */
+int
+OSCEngineReceiver::m_midi_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* patch_path = &argv[1]->s;
+
+ midi_learn(patch_path);
+
+ return 0;
+}
+
+
+#ifdef HAVE_LASH
+/** \page engine_osc_namespace
+ * \b /om/lash/restore_done - Notify LASH restoring is finished and connections can be made.
+ * \arg \b response-id (integer)
+ */
+int
+OSCEngineReceiver::m_lash_restore_done_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ lash_restore_done();
+ return 0;
+}
+#endif // HAVE_LASH
+
+
+/** \page engine_osc_namespace
+ *
\b /om/metadata/set - Sets a piece of metadata, associated with a synth-space object (node, etc)
+ * \arg \b response-id (integer)
+ * \arg \b object-path (string) - Full path of object to associate metadata with
+ * \arg \b key (string) - Key (index) for new piece of metadata
+ * \arg \b value (string) - Value of new piece of metadata
+ */
+int
+OSCEngineReceiver::m_metadata_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* node_path = &argv[1]->s;
+ const char* key = &argv[2]->s;
+ const char* value = &argv[3]->s;
+
+ set_metadata(node_path, key, value);
+
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ *
\b /om/metadata/responder - Requests the engine send a piece of metadata, associated with a synth-space object (node, etc)
+ * \arg \b response-id (integer)
+ * \arg \b object-path (string) - Full path of object metadata is associated with
+ * \arg \b key (string) - Key (index) for piece of metadata
+ *
+ * \li Reply will be sent to client registered with the source address of this message.
\n \n
+ */
+int
+OSCEngineReceiver::m_metadata_get_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ /*
+ const char* node_path = &argv[1]->s;
+ const char* key = &argv[2]->s;
+ */
+ cerr << "FIXME: OSC metadata request\n";
+ // FIXME: Equivalent?
+ /*
+ RequestMetadataEvent* ev = new RequestMetadataEvent(
+ new OSCResponder(ClientKey(addr)),
+ node_path, key);
+
+ */
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/responder/plugins - Requests the engine send a list of all known plugins.
+ * \arg \b response-id (integer)
+ *
+ * \li Reply will be sent to client registered with the source address of this message.
\n \n
+ */
+int
+OSCEngineReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ request_plugins();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc)
+ * \arg \b response-id (integer)
+ *
+ * \li Reply will be sent to client registered with the source address of this message.
\n \n
+ */
+int
+OSCEngineReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ request_all_objects();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * \b /om/responder/port_value - Requests the engine send the value of a port.
+ * \arg \b response-id (integer)
+ * \arg \b port-path (string) - Full path of port to send the value of
\n \n
+ *
+ * \li Reply will be sent to client registered with the source address of this message.
\n \n
+ */
+int
+OSCEngineReceiver::m_request_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ const char* port_path = &argv[1]->s;
+
+ request_port_value(port_path);
+ return 0;
+}
+
+
+#ifdef HAVE_DSSI
+int
+OSCEngineReceiver::m_dssi_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+#if 0
+ string node_path(path);
+
+ if (node_path.substr(0, 5) != "/dssi")
+ return 1;
+
+ string command = node_path.substr(node_path.find_last_of("/")+1);
+ node_path = node_path.substr(5); // chop off leading "/dssi/"
+ node_path = node_path.substr(0, node_path.find_last_of("/")); // chop off command at end
+
+ //cout << "DSSI: Got message " << command << " for node " << node_path << endl;
+
+ QueuedEvent* ev = NULL;
+
+ if (command == "update" && !strcmp(types, "s"))
+ ev = new DSSIUpdateEvent(NULL, node_path, &argv[0]->s);
+ else if (command == "control" && !strcmp(types, "if"))
+ ev = new DSSIControlEvent(NULL, node_path, argv[0]->i, argv[1]->f);
+ else if (command == "configure" && ~strcmp(types, "ss"))
+ ev = new DSSIConfigureEvent(NULL, node_path, &argv[0]->s, &argv[1]->s);
+ else if (command == "program" && ~strcmp(types, "ii"))
+ ev = new DSSIProgramEvent(NULL, node_path, argv[0]->i, argv[1]->i);
+
+ if (ev != NULL)
+ push(ev);
+ else
+ cerr << "[OSCEngineReceiver] Unknown DSSI command received: " << path << endl;
+#endif
+ return 0;
+}
+#endif
+
+
+// Static Callbacks //
+
+
+// Display incoming OSC messages (for debugging purposes)
+int
+OSCEngineReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
+{
+ printf("[OSCMsg] %s\n", path);
+
+ for (int i=0; i < argc; ++i) {
+ printf(" '%c' ", types[i]);
+ lo_arg_pp(lo_type(types[i]), argv[i]);
+ printf("\n");
+ }
+ printf("\n");
+
+ return 1; // not handled
+}
+
+
+int
+OSCEngineReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
+{
+ const lo_address addr = lo_message_get_source(msg);
+ char* const url = lo_address_get_url(addr);
+
+ cerr << "Unknown command " << path << " (" << types << "), sending error.\n";
+
+ string error_msg = "Unknown command: ";
+ error_msg.append(path).append(" ").append(types);
+
+ OSCResponder(0, url).respond_error(error_msg);
+
+ return 0;
+}
+
+
+} // namespace Ingen
diff --git a/src/libs/engine/OSCEngineReceiver.h b/src/libs/engine/OSCEngineReceiver.h
new file mode 100644
index 00000000..cc2d7350
--- /dev/null
+++ b/src/libs/engine/OSCEngineReceiver.h
@@ -0,0 +1,129 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen 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.
+ *
+ * Ingen 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OSCENGINERECEIVER_H
+#define OSCENGINERECEIVER_H
+
+#include "config.h"
+#include
+#include
+#include "QueuedEngineInterface.h"
+#include "OSCResponder.h"
+using std::string;
+
+namespace Ingen {
+
+class JackDriver;
+class NodeFactory;
+class Patch;
+
+
+/* Some boilerplate killing macros... */
+#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg
+
+/* Defines a static handler to be passed to lo_add_method, which is a trivial
+ * wrapper around a non-static method that does the real work. Makes a whoole
+ * lot of ugly boiler plate go away */
+#define LO_HANDLER(name) \
+int m_##name##_cb (LO_HANDLER_ARGS);\
+inline static int name##_cb(LO_HANDLER_ARGS, void* myself)\
+{ return ((OSCEngineReceiver*)myself)->m_##name##_cb(path, types, argv, argc, msg); }
+
+
+/* FIXME: Make this receive and preprocess in the same thread? */
+
+
+/** Receives OSC messages from liblo.
+ *
+ * This inherits from QueuedEngineInterface and calls it's own functions
+ * via OSC. It's not actually a directly callable EngineInterface (it's
+ * callable via OSC...) so it should be implemented-as-a (privately inherit)
+ * QueuedEngineInterface, but it needs to be public so it's an EventSource
+ * the Driver can use. This probably should be fixed somehow..
+ *
+ * \ingroup engine
+ */
+class OSCEngineReceiver : public QueuedEngineInterface
+{
+public:
+ OSCEngineReceiver(Engine& engine, size_t queue_size, const char* const port);
+ ~OSCEngineReceiver();
+
+ void activate();
+ void deactivate();
+
+private:
+ // Prevent copies (undefined)
+ OSCEngineReceiver(const OSCEngineReceiver&);
+ OSCEngineReceiver& operator=(const OSCEngineReceiver&);
+
+ virtual void _run();
+
+ static void error_cb(int num, const char* msg, const char* path);
+ static int set_response_address_cb(LO_HANDLER_ARGS, void* myself);
+ static int generic_cb(LO_HANDLER_ARGS, void* myself);
+ static int unknown_cb(LO_HANDLER_ARGS, void* myself);
+
+ LO_HANDLER(quit);
+ LO_HANDLER(ping);
+ LO_HANDLER(ping_slow);
+ LO_HANDLER(register_client);
+ LO_HANDLER(unregister_client);
+ LO_HANDLER(load_plugins);
+ LO_HANDLER(engine_activate);
+ LO_HANDLER(engine_deactivate);
+ LO_HANDLER(create_patch);
+ LO_HANDLER(rename);
+ LO_HANDLER(create_port);
+ LO_HANDLER(create_node);
+ LO_HANDLER(create_node_by_uri);
+ LO_HANDLER(enable_patch);
+ LO_HANDLER(disable_patch);
+ LO_HANDLER(clear_patch);
+ LO_HANDLER(destroy);
+ LO_HANDLER(connect);
+ LO_HANDLER(disconnect);
+ LO_HANDLER(disconnect_all);
+ LO_HANDLER(set_port_value);
+ LO_HANDLER(set_port_value_voice);
+ LO_HANDLER(set_port_value_slow);
+ LO_HANDLER(note_on);
+ LO_HANDLER(note_off);
+ LO_HANDLER(all_notes_off);
+ LO_HANDLER(midi_learn);
+ LO_HANDLER(metadata_get);
+ LO_HANDLER(metadata_set);
+ LO_HANDLER(request_plugins);
+ LO_HANDLER(request_all_objects);
+ LO_HANDLER(request_port_value);
+#ifdef HAVE_DSSI
+ LO_HANDLER(dssi);
+#endif
+#ifdef HAVE_LASH
+ LO_HANDLER(lash_restore_done);
+#endif
+
+ const char* const _port;
+ lo_server _server;
+
+ /** Cached OSC responder (for most recent incoming message) */
+ CountedPtr _osc_responder;
+};
+
+
+} // namespace Ingen
+
+#endif // OSCENGINERECEIVER_H
diff --git a/src/libs/engine/OSCReceiver.cpp b/src/libs/engine/OSCReceiver.cpp
deleted file mode 100644
index 5c08c17a..00000000
--- a/src/libs/engine/OSCReceiver.cpp
+++ /dev/null
@@ -1,909 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "OSCReceiver.h"
-#include
-#include
-#include
-#include
-#include "types.h"
-#include "util/Queue.h"
-#include "util/CountedPtr.h"
-#include "QueuedEventSource.h"
-#include "interface/ClientKey.h"
-#include "interface/ClientInterface.h"
-#include "OSCClient.h"
-#include "OSCResponder.h"
-#include "ClientBroadcaster.h"
-
-using std::cerr; using std::cout; using std::endl;
-
-namespace Ingen {
-
-using Shared::ClientKey;
-
-
-/*! \page engine_osc_namespace Engine OSC Namespace Documentation
- *
- * These are the commands the engine recognizes. A client can control every
- * aspect of the engine entirely with these commands.
- *
- * All commands on this page are in the "control band". If a client needs to
- * know about the state of the engine, it must listen to the "notification band".
- * See the "Client OSC Namespace Documentation" for details.
- */
-
-
-OSCReceiver::OSCReceiver(Engine& engine, size_t queue_size, const char* const port)
-: QueuedEngineInterface(engine, queue_size, queue_size), // FIXME
- _port(port),
- _server(NULL),
- _osc_responder(NULL)
-{
- _server = lo_server_new(port, error_cb);
-
- if (_server == NULL) {
- cerr << "[OSC] Could not start OSC server. Aborting." << endl;
- exit(EXIT_FAILURE);
- } else {
- char* lo_url = lo_server_get_url(_server);
- cout << "[OSC] Started OSC server at " << lo_url << endl;
- free(lo_url);
- }
-
- // For debugging, print all incoming OSC messages
- lo_server_add_method(_server, NULL, NULL, generic_cb, NULL);
-
- // Set response address for this message.
- // It's important this is first and returns nonzero.
- lo_server_add_method(_server, NULL, NULL, set_response_address_cb, this);
-
- // Commands
- lo_server_add_method(_server, "/om/ping", "i", ping_cb, this);
- lo_server_add_method(_server, "/om/ping_slow", "i", ping_slow_cb, this);
- lo_server_add_method(_server, "/om/engine/quit", "i", quit_cb, this);
- //lo_server_add_method(_server, "/om/engine/register_client", "is", register_client_cb, this);
- lo_server_add_method(_server, "/om/engine/register_client", "i", register_client_cb, this);
- lo_server_add_method(_server, "/om/engine/unregister_client", "i", unregister_client_cb, this);
- lo_server_add_method(_server, "/om/engine/load_plugins", "i", load_plugins_cb, this);
- lo_server_add_method(_server, "/om/engine/activate", "i", engine_activate_cb, this);
- lo_server_add_method(_server, "/om/engine/deactivate", "i", engine_deactivate_cb, this);
- lo_server_add_method(_server, "/om/synth/create_patch", "isi", create_patch_cb, this);
- lo_server_add_method(_server, "/om/synth/enable_patch", "is", enable_patch_cb, this);
- lo_server_add_method(_server, "/om/synth/disable_patch", "is", disable_patch_cb, this);
- lo_server_add_method(_server, "/om/synth/clear_patch", "is", clear_patch_cb, this);
- lo_server_add_method(_server, "/om/synth/create_port", "issi", create_port_cb, this);
- lo_server_add_method(_server, "/om/synth/create_node", "issssi", create_node_cb, this);
- lo_server_add_method(_server, "/om/synth/create_node", "isssi", create_node_by_uri_cb, this);
- lo_server_add_method(_server, "/om/synth/destroy", "is", destroy_cb, this);
- lo_server_add_method(_server, "/om/synth/rename", "iss", rename_cb, this);
- lo_server_add_method(_server, "/om/synth/connect", "iss", connect_cb, this);
- lo_server_add_method(_server, "/om/synth/disconnect", "iss", disconnect_cb, this);
- lo_server_add_method(_server, "/om/synth/disconnect_all", "is", disconnect_all_cb, this);
- lo_server_add_method(_server, "/om/synth/set_port_value", "isf", set_port_value_cb, this);
- lo_server_add_method(_server, "/om/synth/set_port_value", "isif", set_port_value_voice_cb, this);
- lo_server_add_method(_server, "/om/synth/set_port_value_slow", "isf", set_port_value_slow_cb, this);
- lo_server_add_method(_server, "/om/synth/note_on", "isii", note_on_cb, this);
- lo_server_add_method(_server, "/om/synth/note_off", "isi", note_off_cb, this);
- lo_server_add_method(_server, "/om/synth/all_notes_off", "isi", all_notes_off_cb, this);
- lo_server_add_method(_server, "/om/synth/midi_learn", "is", midi_learn_cb, this);
-#ifdef HAVE_LASH
- lo_server_add_method(_server, "/om/lash/restore_finished", "i", lash_restore_done_cb, this);
-#endif
-
- lo_server_add_method(_server, "/om/metadata/request", "isss", metadata_get_cb, this);
- lo_server_add_method(_server, "/om/metadata/set", "isss", metadata_set_cb, this);
-
- // Queries
- lo_server_add_method(_server, "/om/request/plugins", "i", request_plugins_cb, this);
- lo_server_add_method(_server, "/om/request/all_objects", "i", request_all_objects_cb, this);
- lo_server_add_method(_server, "/om/request/port_value", "is", request_port_value_cb, this);
-
- // DSSI support
-#ifdef HAVE_DSSI
- // XXX WARNING: notice this is a catch-all
- lo_server_add_method(_server, NULL, NULL, dssi_cb, this);
-#endif
-
- lo_server_add_method(_server, NULL, NULL, unknown_cb, NULL);
-}
-
-
-OSCReceiver::~OSCReceiver()
-{
- deactivate();
-
- if (_server != NULL) {
- lo_server_free(_server);
- _server = NULL;
- }
-}
-
-
-void
-OSCReceiver::activate()
-{
- set_name("OSCReceiver");
- QueuedEventSource::activate();
- set_scheduling(SCHED_FIFO, 10);
-}
-
-
-void
-OSCReceiver::deactivate()
-{
- cout << "[OSCReceiver] Stopped OSC listening thread" << endl;
- QueuedEventSource::deactivate();
-}
-
-
-/** Override the semaphore driven _run method of QueuedEngineInterface
- * to wait on OSC messages and prepare them right away in the same thread.
- */
-void
-OSCReceiver::_run()
-{
- /* get a timestamp here and stamp all the events with the same time so
- * they all get executed in the same cycle */
-
- while (true) {
- assert( ! unprepared_events());
-
- // Wait on a message and enqueue it
- lo_server_recv(_server);
-
- // Enqueue every other message that is here "now"
- // (would this provide truly atomic bundles?)
- while (lo_server_recv_noblock(_server, 0) > 0) ;
-
- // Process them all
- while (unprepared_events())
- _whipped(); // Whip our slave self
-
- // No more unprepared events
- }
-}
-
-
-/** Create a new responder for this message, if necessary.
- *
- * This is based on the fact that the current responder is stored in a ref
- * counted pointer, and events just take a reference to that. Thus, events
- * may delete their responder if we've since switched to a new one, or the
- * same one can stay around and serve a series of events. Reference counting
- * is pretty sweet, eh?
- *
- * If this message came from the same source as the last message, no allocation
- * of responders or lo_addresses or any of it needs to be done. Unfortunately
- * the only way to check is by comparing URLs, because liblo addresses suck.
- *
- * Really, this entire thing is a basically just a crafty way of partially
- * working around the fact that liblo addresses really suck. Oh well.
- */
-int
-OSCReceiver::set_response_address_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
-{
- OSCReceiver* const me = reinterpret_cast(user_data);
-
- //cerr << "SET RESPONSE\n";
-
- if (argc < 1 || types[0] != 'i') // Not a valid Ingen message
- return 0; // Save liblo the trouble
-
- //cerr << "** valid msg\n";
-
- const int id = argv[0]->i;
-
- // Need to respond
- if (id != -1) {
- const lo_address addr = lo_message_get_source(msg);
- char* const url = lo_address_get_url(addr);
-
- //cerr << "** need to respond\n";
-
- // Currently have an OSC responder, check if it's still okay
- if (me->_responder == me->_osc_responder) {
- //cerr << "** osc responder\n";
-
- if (!strcmp(url, me->_osc_responder->url())) {
- // Nice one, same address
- //cerr << "** Using cached response address, hooray" << endl;
- } else {
- // Shitty deal, make a new one
- //cerr << "** Setting response address to " << url << "(2)" << endl;
- me->_osc_responder = CountedPtr(new OSCResponder(id, url));
- me->set_responder(me->_osc_responder);
- // (responder takes ownership of url, no leak)
- }
-
- // Otherwise we have a NULL responder, definitely need to set a new one
- } else {
- //cerr << "** null responder\n";
- me->_osc_responder = CountedPtr(new OSCResponder(id, url));
- me->set_responder(me->_osc_responder);
- //cerr << "** Setting response address to " << url << "(2)" << endl;
- }
-
- // Don't respond
- } else {
- me->disable_responses();
- //cerr << "** Not responding." << endl;
- }
-
- // If this returns 0 no OSC commands will work
- return 1;
-}
-
-
-void
-OSCReceiver::error_cb(int num, const char* msg, const char* path)
-{
- cerr << "liblo server error " << num << " in path \"" << "\" - " << msg << endl;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/ping - Immediately sends a successful response to the given response id.
- * \arg \b response-id (integer)
\n \n
- */
-int
-OSCReceiver::m_ping_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- _responder->respond_ok();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/ping_slow - Sends response after going through the ("slow") event queue.
- * \arg \b response-id (integer)
- *
- * \li See the documentation for /om/synth/set_port_value_slow for an explanation of how
- * this differs from /om/ping. This is useful to send after sending a large cluster of
- * events as a sentinel and wait on it's response, to know when the events are all
- * finished processing.
\n \n
- */
-int
-OSCReceiver::m_ping_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- ping();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/engine/quit - Terminates the engine.
- * \arg \b response-id (integer)
- *
- * \li Note that there is NO order guarantees with this command at all. You could
- * send 10 messages then quit, and the quit reply could come immediately and the
- * 10 messages would never get executed.
\n \n
- */
-int
-OSCReceiver::m_quit_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
-
- quit();
- return 0;
-}
-
-/** \page engine_osc_namespace
- * \b /om/engine/register_client - Registers a new client with the engine
- * \arg \b response-id (integer)
- *
- * The incoming address will be used for the new registered client. If you
- * want to register a different specific address, use the URL version.
- */
-int
-OSCReceiver::m_register_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- lo_address addr = lo_message_get_source(msg);
-
- char* const url = lo_address_get_url(addr);
- CountedPtr client(new OSCClient((const char*)url));
- register_client(ClientKey(ClientKey::OSC_URL, (const char*)url), client);
- free(url);
-
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/engine/unregister_client - Unregisters a client
- * \arg \b response-id (integer)
\n \n
- */
-int
-OSCReceiver::m_unregister_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- lo_address addr = lo_message_get_source(msg);
-
- char* url = lo_address_get_url(addr);
- unregister_client(ClientKey(ClientKey::OSC_URL, url));
- free(url);
-
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/engine/load_plugins - Locates all available plugins, making them available for use.
- * \arg \b response-id (integer)
\n \n
- */
-int
-OSCReceiver::m_load_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- load_plugins();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/engine/activate - Activate the engine (MIDI, audio, everything)
- * \arg \b response-id (integer)
- *
- * \li Note that you must send this message first if you want the engine to do
- * anything at all - including respond to your messages! \n \n
- */
-int
-OSCReceiver::m_engine_activate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- QueuedEngineInterface::activate();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/engine/deactivate - Deactivate the engine completely.
- * \arg \b response-id (integer)
\n \n
- */
-int
-OSCReceiver::m_engine_deactivate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- QueuedEngineInterface::deactivate();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/create_patch - Creates a new, empty, toplevel patch.
- * \arg \b response-id (integer)
- * \arg \b patch-path (string) - Patch path (complete, ie /master/parent/new_patch)
- * \arg \b poly (integer) - Patch's (internal) polyphony
\n \n
- */
-int
-OSCReceiver::m_create_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* patch_path = &argv[1]->s;
- const int poly = argv[2]->i;
-
- create_patch(patch_path, poly);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/rename - Rename an Object (only Nodes, for now)
- * \arg \b response-id (integer)
- * \arg \b path - Object's path
- * \arg \b name - New name for object
\n \n
- */
-int
-OSCReceiver::m_rename_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* object_path = &argv[1]->s;
- const char* name = &argv[2]->s;
-
- rename(object_path, name);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/enable_patch - Enable DSP processing of a patch
- * \arg \b response-id (integer)
- * \arg \b patch-path - Patch's path
- */
-int
-OSCReceiver::m_enable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* patch_path = &argv[1]->s;
-
- enable_patch(patch_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/synth/disable_patch - Disable DSP processing of a patch
- * \arg \b response-id (integer)
- * \arg \b patch-path - Patch's path
- */
-int
-OSCReceiver::m_disable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* patch_path = &argv[1]->s;
-
- disable_patch(patch_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/synth/clear_patch - Remove all nodes from a patch
- * \arg \b response-id (integer)
- * \arg \b patch-path - Patch's path
- */
-int
-OSCReceiver::m_clear_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* patch_path = &argv[1]->s;
-
- clear_patch(patch_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/synth/create_port - Add a port into a given patch (load a plugin by URI)
- * \arg \b response-id (integer)
- * \arg \b path (string) - Full path of the new port (ie. /patch2/subpatch/newport)
- * \arg \b data-type (string) - Data type for port to contain ("AUDIO", "CONTROL", or "MIDI")
- * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1)
\n \n
- */
-int
-OSCReceiver::m_create_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[1]->s;
- const char* data_type = &argv[2]->s;
- const int direction = argv[3]->i;
-
- create_port(port_path, data_type, (direction == 1));
- return 0;
-}
-
-/** \page engine_osc_namespace
- * \b /om/synth/create_node - Add a node into a given patch (load a plugin by URI)
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode)
- * \arg \b type (string) - Plugin type ("Internal", "LV2", "DSSI", "LADSPA")
- * \arg \b plug-uri (string) - URI of the plugin to load
- * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)
\n \n
- */
-int
-OSCReceiver::m_create_node_by_uri_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[1]->s;
- const char* type = &argv[2]->s;
- const char* plug_uri = &argv[3]->s;
- const int poly = argv[4]->i;
-
- // FIXME: make sure poly is valid
-
- create_node(node_path, type, plug_uri, (poly == 1));
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/create_node - Add a node into a given patch (load a plugin by libname, label) \b DEPRECATED
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode)
- * \arg \b type (string) - Plugin type ("LADSPA" or "Internal")
- * \arg \b lib-name (string) - Name of library where plugin resides (eg "cmt.so")
- * \arg \b plug-label (string) - Label (ID) of plugin (eg "sine_fcaa")
- * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)
- *
- * \li This is only here to provide backwards compatibility for old patches that store LADSPA plugin
- * references as libname, label. It is to be removed ASAP, don't use it.
- *
\n \n
- */
-int
-OSCReceiver::m_create_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[1]->s;
- const char* type = &argv[2]->s;
- const char* lib_name = &argv[3]->s;
- const char* plug_label = &argv[4]->s;
- const int poly = argv[5]->i;
-
- create_node(node_path, type, lib_name, plug_label, (poly == 1));
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/destroy - Removes (destroys) a Patch or a Node
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Full path of the object
\n \n
- */
-int
-OSCReceiver::m_destroy_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[1]->s;
-
- destroy(node_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/connect - Connects two ports (must be in the same patch)
- * \arg \b response-id (integer)
- * \arg \b src-port-path (string) - Full path of source port
- * \arg \b dst-port-path (string) - Full path of destination port
\n \n
- */
-int
-OSCReceiver::m_connect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* src_port_path = &argv[1]->s;
- const char* dst_port_path = &argv[2]->s;
-
- connect(src_port_path, dst_port_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/disconnect - Disconnects two ports.
- * \arg \b response-id (integer)
- * \arg \b src-port-path (string) - Full path of source port
- * \arg \b dst-port-path (string) - Full path of destination port
\n \n
- */
-int
-OSCReceiver::m_disconnect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* src_port_path = &argv[1]->s;
- const char* dst_port_path = &argv[2]->s;
-
- disconnect(src_port_path, dst_port_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/disconnect_all - Disconnect all connections to/from a node.
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Full path of node.
\n \n
- */
-int
-OSCReceiver::m_disconnect_all_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[1]->s;
-
- disconnect_all(node_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/set_port_value - Sets the value of a port for all voices (both AR and CR)
- * \arg \b response-id (integer)
- * \arg \b port-path (string) - Name of port
- * \arg \b value (float) - Value to set port to
- */
-int
-OSCReceiver::m_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[1]->s;
- const float value = argv[2]->f;
-
- set_port_value(port_path, value);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/synth/set_port_value - Sets the value of a port for a specific voice (both AR and CR)
- * \arg \b response-id (integer)
- * \arg \b port-path (string) - Name of port
- * \arg \b voice (integer) - Voice to set port value for
- * \arg \b value (float) - Value to set port to
- */
-int
-OSCReceiver::m_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[1]->s;
- const int voice = argv[2]->i;
- const float value = argv[3]->f;
-
- set_port_value(port_path, voice, value);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/synth/set_port_value_slow - Sets the value of a port for all voices (as a QueuedEvent)
- * \arg \b response-id (integer)
- * \arg \b port-path (string) - Name of port
- * \arg \b value (float) - Value to set port to
- *
- * \li This version exists so you can send it immediately after a QueuedEvent it may depend on (ie a
- * node creation) and be sure it happens after the event (a normal set_port_value could beat the
- * slow event and arrive out of order).
\n \n
- */
-int
-OSCReceiver::m_set_port_value_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[1]->s;
- const float value = argv[2]->f;
-
- set_port_value_queued(port_path, value);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/note_on - Triggers a note-on, just as if it came from MIDI
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node)
- * \arg \b note-num (int) - MIDI style note number (0-127)
- * \arg \b velocity (int) - MIDI style velocity (0-127)
\n \n
- */
-int
-OSCReceiver::m_note_on_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- /*
-
- const char* node_path = &argv[1]->s;
- const uchar note_num = argv[2]->i;
- const uchar velocity = argv[3]->i;
- */
- cerr << "FIXME: OSC note on\n";
- //note_on(node_path, note_num, velocity);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/note_off - Triggers a note-off, just as if it came from MIDI
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node)
- * \arg \b note-num (int) - MIDI style note number (0-127)
\n \n
- */
-int
-OSCReceiver::m_note_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- /*
-
- const char* patch_path = &argv[1]->s;
- const uchar note_num = argv[2]->i;
- */
- cerr << "FIXME: OSC note off\n";
- //note_off(patch_path, note_num);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/all_notes_off - Triggers a note-off for all voices, just as if it came from MIDI
- * \arg \b response-id (integer)
- * \arg \b patch-path (string) - Patch of patch to send event to
\n \n
- */
-int
-OSCReceiver::m_all_notes_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- /*
-
- const char* patch_path = &argv[1]->s;
- */
- cerr << "FIXME: OSC all notes off\n";
- //all_notes_off(patch_path);
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/synth/midi_learn - Initiate MIDI learn for a given (MIDI Control) Node
- * \arg \b response-id (integer)
- * \arg \b node-path (string) - Patch of the Node that should learn the next MIDI event.
- *
- * \li This of course will only do anything for MIDI control nodes. The node will learn the next MIDI
- * event that arrives at it's MIDI input port - no behind the scenes voodoo happens here. It is planned
- * that a plugin specification supporting arbitrary OSC commands for plugins will exist one day, and this
- * method will go away completely.
\n \n
- */
-int
-OSCReceiver::m_midi_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* patch_path = &argv[1]->s;
-
- midi_learn(patch_path);
-
- return 0;
-}
-
-
-#ifdef HAVE_LASH
-/** \page engine_osc_namespace
- * \b /om/lash/restore_done - Notify LASH restoring is finished and connections can be made.
- * \arg \b response-id (integer)
- */
-int
-OSCReceiver::m_lash_restore_done_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- lash_restore_done();
- return 0;
-}
-#endif // HAVE_LASH
-
-
-/** \page engine_osc_namespace
- *
\b /om/metadata/set - Sets a piece of metadata, associated with a synth-space object (node, etc)
- * \arg \b response-id (integer)
- * \arg \b object-path (string) - Full path of object to associate metadata with
- * \arg \b key (string) - Key (index) for new piece of metadata
- * \arg \b value (string) - Value of new piece of metadata
- */
-int
-OSCReceiver::m_metadata_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* node_path = &argv[1]->s;
- const char* key = &argv[2]->s;
- const char* value = &argv[3]->s;
-
- set_metadata(node_path, key, value);
-
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- *
\b /om/metadata/responder - Requests the engine send a piece of metadata, associated with a synth-space object (node, etc)
- * \arg \b response-id (integer)
- * \arg \b object-path (string) - Full path of object metadata is associated with
- * \arg \b key (string) - Key (index) for piece of metadata
- *
- * \li Reply will be sent to client registered with the source address of this message.
\n \n
- */
-int
-OSCReceiver::m_metadata_get_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- /*
- const char* node_path = &argv[1]->s;
- const char* key = &argv[2]->s;
- */
- cerr << "FIXME: OSC metadata request\n";
- // FIXME: Equivalent?
- /*
- RequestMetadataEvent* ev = new RequestMetadataEvent(
- new OSCResponder(ClientKey(addr)),
- node_path, key);
-
- */
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/responder/plugins - Requests the engine send a list of all known plugins.
- * \arg \b response-id (integer)
- *
- * \li Reply will be sent to client registered with the source address of this message.
\n \n
- */
-int
-OSCReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- request_plugins();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc)
- * \arg \b response-id (integer)
- *
- * \li Reply will be sent to client registered with the source address of this message.
\n \n
- */
-int
-OSCReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- request_all_objects();
- return 0;
-}
-
-
-/** \page engine_osc_namespace
- * \b /om/responder/port_value - Requests the engine send the value of a port.
- * \arg \b response-id (integer)
- * \arg \b port-path (string) - Full path of port to send the value of
\n \n
- *
- * \li Reply will be sent to client registered with the source address of this message.
\n \n
- */
-int
-OSCReceiver::m_request_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
- const char* port_path = &argv[1]->s;
-
- request_port_value(port_path);
- return 0;
-}
-
-
-#ifdef HAVE_DSSI
-int
-OSCReceiver::m_dssi_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
-{
-#if 0
- string node_path(path);
-
- if (node_path.substr(0, 5) != "/dssi")
- return 1;
-
- string command = node_path.substr(node_path.find_last_of("/")+1);
- node_path = node_path.substr(5); // chop off leading "/dssi/"
- node_path = node_path.substr(0, node_path.find_last_of("/")); // chop off command at end
-
- //cout << "DSSI: Got message " << command << " for node " << node_path << endl;
-
- QueuedEvent* ev = NULL;
-
- if (command == "update" && !strcmp(types, "s"))
- ev = new DSSIUpdateEvent(NULL, node_path, &argv[0]->s);
- else if (command == "control" && !strcmp(types, "if"))
- ev = new DSSIControlEvent(NULL, node_path, argv[0]->i, argv[1]->f);
- else if (command == "configure" && ~strcmp(types, "ss"))
- ev = new DSSIConfigureEvent(NULL, node_path, &argv[0]->s, &argv[1]->s);
- else if (command == "program" && ~strcmp(types, "ii"))
- ev = new DSSIProgramEvent(NULL, node_path, argv[0]->i, argv[1]->i);
-
- if (ev != NULL)
- push(ev);
- else
- cerr << "[OSCReceiver] Unknown DSSI command received: " << path << endl;
-#endif
- return 0;
-}
-#endif
-
-
-// Static Callbacks //
-
-
-// Display incoming OSC messages (for debugging purposes)
-int
-OSCReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
-{
- printf("[OSCMsg] %s\n", path);
-
- for (int i=0; i < argc; ++i) {
- printf(" '%c' ", types[i]);
- lo_arg_pp(lo_type(types[i]), argv[i]);
- printf("\n");
- }
- printf("\n");
-
- return 1; // not handled
-}
-
-
-int
-OSCReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data)
-{
- const lo_address addr = lo_message_get_source(msg);
- char* const url = lo_address_get_url(addr);
-
- cerr << "Unknown command " << path << " (" << types << "), sending error.\n";
-
- string error_msg = "Unknown command: ";
- error_msg.append(path).append(" ").append(types);
-
- OSCResponder(0, url).respond_error(error_msg);
-
- return 0;
-}
-
-
-} // namespace Ingen
diff --git a/src/libs/engine/OSCReceiver.h b/src/libs/engine/OSCReceiver.h
deleted file mode 100644
index 671944fd..00000000
--- a/src/libs/engine/OSCReceiver.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen 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.
- *
- * Ingen 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef OSCRECEIVER_H
-#define OSCRECEIVER_H
-
-#include "config.h"
-#include
-#include
-#include "QueuedEngineInterface.h"
-#include "OSCResponder.h"
-using std::string;
-
-namespace Ingen {
-
-class JackDriver;
-class NodeFactory;
-class Patch;
-
-
-/* Some boilerplate killing macros... */
-#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg
-
-/* Defines a static handler to be passed to lo_add_method, which is a trivial
- * wrapper around a non-static method that does the real work. Makes a whoole
- * lot of ugly boiler plate go away */
-#define LO_HANDLER(name) \
-int m_##name##_cb (LO_HANDLER_ARGS);\
-inline static int name##_cb(LO_HANDLER_ARGS, void* osc_receiver)\
-{ return ((OSCReceiver*)osc_receiver)->m_##name##_cb(path, types, argv, argc, msg); }
-
-
-/* FIXME: Make this receive and preprocess in the same thread? */
-
-
-/** Receives OSC messages from liblo.
- *
- * This inherits from QueuedEngineInterface and calls it's own functions
- * via OSC. It's not actually a directly callable EngineInterface (it's
- * callable via OSC...) so it should be implemented-as-a (privately inherit)
- * QueuedEngineInterface, but it needs to be public so it's an EventSource
- * the Driver can use. This probably should be fixed somehow..
- *
- * \ingroup engine
- */
-class OSCReceiver : public QueuedEngineInterface
-{
-public:
- OSCReceiver(Engine& engine, size_t queue_size, const char* const port);
- ~OSCReceiver();
-
- void activate();
- void deactivate();
-
-private:
- // Prevent copies (undefined)
- OSCReceiver(const OSCReceiver&);
- OSCReceiver& operator=(const OSCReceiver&);
-
- virtual void _run();
-
- static void error_cb(int num, const char* msg, const char* path);
- static int set_response_address_cb(LO_HANDLER_ARGS, void* osc_receiver);
- static int generic_cb(LO_HANDLER_ARGS, void* osc_receiver);
- static int unknown_cb(LO_HANDLER_ARGS, void* osc_receiver);
-
- LO_HANDLER(quit);
- LO_HANDLER(ping);
- LO_HANDLER(ping_slow);
- LO_HANDLER(register_client);
- LO_HANDLER(unregister_client);
- LO_HANDLER(load_plugins);
- LO_HANDLER(engine_activate);
- LO_HANDLER(engine_deactivate);
- LO_HANDLER(create_patch);
- LO_HANDLER(rename);
- LO_HANDLER(create_port);
- LO_HANDLER(create_node);
- LO_HANDLER(create_node_by_uri);
- LO_HANDLER(enable_patch);
- LO_HANDLER(disable_patch);
- LO_HANDLER(clear_patch);
- LO_HANDLER(destroy);
- LO_HANDLER(connect);
- LO_HANDLER(disconnect);
- LO_HANDLER(disconnect_all);
- LO_HANDLER(set_port_value);
- LO_HANDLER(set_port_value_voice);
- LO_HANDLER(set_port_value_slow);
- LO_HANDLER(note_on);
- LO_HANDLER(note_off);
- LO_HANDLER(all_notes_off);
- LO_HANDLER(midi_learn);
- LO_HANDLER(metadata_get);
- LO_HANDLER(metadata_set);
- LO_HANDLER(request_plugins);
- LO_HANDLER(request_all_objects);
- LO_HANDLER(request_port_value);
-#ifdef HAVE_DSSI
- LO_HANDLER(dssi);
-#endif
-#ifdef HAVE_LASH
- LO_HANDLER(lash_restore_done);
-#endif
-
- const char* const _port;
- lo_server _server;
-
- /** Cached OSC responder (for most recent incoming message) */
- CountedPtr _osc_responder;
-};
-
-
-} // namespace Ingen
-
-#endif // OSCRECEIVER_H
diff --git a/src/libs/engine/QueuedEventSource.cpp b/src/libs/engine/QueuedEventSource.cpp
index 0ef11ac1..915b7811 100644
--- a/src/libs/engine/QueuedEventSource.cpp
+++ b/src/libs/engine/QueuedEventSource.cpp
@@ -16,6 +16,7 @@
#include "QueuedEventSource.h"
#include "QueuedEvent.h"
+#include "PostProcessor.h"
#include
#include
using std::cout; using std::cerr; using std::endl;
@@ -64,12 +65,43 @@ QueuedEventSource::push_queued(QueuedEvent* const ev)
}
+/** Process all events for a cycle.
+ *
+ * Executed events will be pushed to @a dest.
+ */
void
-QueuedEventSource::push_stamped(Event* const ev)
+QueuedEventSource::process(PostProcessor& dest, SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end)
{
- _stamped_queue.push(ev);
+ Event* ev = NULL;
+
+ /* Limit the maximum number of queued events to process per cycle. This
+ * makes the process callback (more) realtime-safe by preventing being
+ * choked by events coming in faster than they can be processed.
+ * FIXME: test this and figure out a good value */
+ const unsigned int MAX_QUEUED_EVENTS = nframes / 100;
+
+ unsigned int num_events_processed = 0;
+
+ /* FIXME: Merge these next two loops into one */
+
+ while ((ev = pop_earliest_queued_before(cycle_end))) {
+ ev->execute(nframes, cycle_start, cycle_end);
+ dest.push(ev);
+ if (++num_events_processed > MAX_QUEUED_EVENTS)
+ break;
+ }
+
+ while ((ev = pop_earliest_stamped_before(cycle_end))) {
+ ev->execute(nframes, cycle_start, cycle_end);
+ dest.push(ev);
+ ++num_events_processed;
+ }
+
+ if (num_events_processed > 0)
+ dest.whip();
}
+
/** Pops the prepared event at the front of the prepare queue, if it exists.
*
* This method will only pop events that have been prepared, and are
diff --git a/src/libs/engine/QueuedEventSource.h b/src/libs/engine/QueuedEventSource.h
index abdea293..f6be92d7 100644
--- a/src/libs/engine/QueuedEventSource.h
+++ b/src/libs/engine/QueuedEventSource.h
@@ -29,6 +29,7 @@
namespace Ingen {
class QueuedEvent;
+class PostProcessor;
/** Queue of events that need processing before reaching the audio thread.
@@ -50,14 +51,16 @@ public:
void activate() { Slave::start(); }
void deactivate() { Slave::stop(); }
- Event* pop_earliest_queued_before(const SampleCount time);
- inline Event* pop_earliest_stamped_before(const SampleCount time);
+ void process(PostProcessor& dest, SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end);
void unblock();
protected:
void push_queued(QueuedEvent* const ev);
- void push_stamped(Event* const ev);
+ inline void push_stamped(Event* const ev) { _stamped_queue.push(ev); }
+
+ Event* pop_earliest_queued_before(const SampleCount time);
+ inline Event* pop_earliest_stamped_before(const SampleCount time);
bool unprepared_events() { return (_prepared_back != _back); }
--
cgit v1.2.1