From 43d51948ccae71b8f0a1c1710e25cf36da8d7d7c Mon Sep 17 00:00:00 2001
From: David Robillard 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). \b /om/response/ok - Respond successfully to a user command
- * \arg \b responder-id (int) - Responder ID this is a response to
- * \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)
- * \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. \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. \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. \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")
- * \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. \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. \b /om/destroyed - Notification an object has been destroyed
- * \arg \b path (string) - Path of object (which no longer exists) \b /om/patch_cleared - Notification a patch has been cleared (all children destroyed)
- * \arg \b path (string) - Path of patch (which is now empty) \b /om/patch_enabled - Notification a patch's DSP processing has been enabled.
- * \arg \b path (string) - Path of enabled patch \b /om/patch_disabled - Notification a patch's DSP processing has been disabled.
- * \arg \b path (string) - Path of disabled patch \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 \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 \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) \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! \b /om/plugin - Notification of the existance of a plugin
- * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")Notification Band
- */
-
-/** \page client_osc_namespace
- * Notification Band
- */
-
-/** \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\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 (TreeThese 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 + *\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 + *\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\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\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\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\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 + +#includeThese 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 \b /om/ping - Immediately sends a successful response to the given response id.
+ * \arg \b response-id (integer) \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. \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. \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 \b /om/engine/unregister_client - Unregisters a client
+ * \arg \b response-id (integer) \b /om/engine/load_plugins - Locates all available plugins, making them available for use.
+ * \arg \b response-id (integer) \b /om/engine/activate - Activate the engine (MIDI, audio, everything)
+ * \arg \b response-id (integer) \b /om/engine/deactivate - Deactivate the engine completely.
+ * \arg \b response-id (integer) \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 \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 \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) \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) \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.
+ * \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 \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 \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 \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. \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). \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) \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) \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 \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. \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. \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. \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. \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 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 \b /om/ping - Immediately sends a successful response to the given response id.
- * \arg \b response-id (integer) \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. \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. \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 \b /om/engine/unregister_client - Unregisters a client
- * \arg \b response-id (integer) \b /om/engine/load_plugins - Locates all available plugins, making them available for use.
- * \arg \b response-id (integer) \b /om/engine/activate - Activate the engine (MIDI, audio, everything)
- * \arg \b response-id (integer) \b /om/engine/deactivate - Deactivate the engine completely.
- * \arg \b response-id (integer) \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 \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 \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) \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) \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.
- * \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 \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 \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 \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. \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). \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) \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) \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 \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. \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. \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. \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. \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