/* This file is part of Ingen.
* Copyright (C) 2007 Dave Robillard 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. \b /ingen/ping - Immediately sends a successful response to the given response id.
* \arg \b response-id (integer) \b /ingen/ping_queued - Sends response after going through the event queue.
* \arg \b response-id (integer)
*
* \li See the documentation for /ingen/set_port_value_queued for an explanation of how
* this differs from /ingen/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 /ingen/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 /ingen/register_client - Registers a new client with the engine
* \arg \b response-id (integer) \n\n
* \li The incoming address will be used for the new registered client. If you
* want to register a different specific address, use the URL version. \b /ingen/unregister_client - Unregisters a client
* \arg \b response-id (integer) \b /ingen/load_plugins - Locates all available plugins, making them available for use.
* \arg \b response-id (integer) \b /ingen/activate - Activate the engine (MIDI, audio, everything)
* \arg \b response-id (integer) \b /ingen/deactivate - Deactivate the engine completely.
* \arg \b response-id (integer) \b /ingen/new_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 /ingen/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 /ingen/clear_patch - Remove all nodes from a patch
* \arg \b response-id (integer)
* \arg \b patch-path - Patch's path \b /ingen/set_polyphony - Set the polyphony of a patch
* \arg \b response-id (integer)
* \arg \b patch-path - Patch's path
* \arg \b poly (integer) \b /ingen/set_polyphonic - Toggle a node's or port's polyphonic mode
* \arg \b response-id (integer)
* \arg \b path - Object's path
* \arg \b polyphonic (bool) \b /ingen/new_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) - Type of port (lv2:AudioPort, lv2:ControlPort, lv2ev:EventPort)
* \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1) \b /ingen/new_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 plug-uri (string) - URI of the plugin to load \n \n
*/
int
OSCEngineReceiver::_new_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* plug_uri = &argv[2]->s;
new_node(node_path, plug_uri);
return 0;
}
/** \page engine_osc_namespace
* \b /ingen/new_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") \n \n
*
* \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 /ingen/destroy - Removes (destroys) a Patch or a Node
* \arg \b response-id (integer)
* \arg \b node-path (string) - Full path of the object \b /ingen/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 /ingen/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 /ingen/disconnect_all - Disconnect all connections to/from a node/port.
* \arg \b response-id (integer)
* \arg \b patch-path (string) - The (parent) patch in which to disconnect object.
\b /ingen/set_port_value - 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.
\n \n */ int OSCEngineReceiver::_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { if (argc < 3 || argc > 5 || strncmp(types, "is", 2)) return 1; const char* port_path = &argv[1]->s; using Raul::Atom; if (!strcmp(types, "isf")) { // float, all voices const float value = argv[2]->f; set_port_value(port_path, Atom(value)); } else if (!strcmp(types, "isif")) { // float, specific voice const float value = argv[3]->f; set_voice_value(port_path, argv[2]->i, Atom(value)); } else if (!strcmp(types, "issb")) { // blob (event), all voices const char* type = &argv[2]->s; lo_blob b = argv[3]; size_t data_size = lo_blob_datasize(b); void* data = lo_blob_dataptr(b); set_port_value(port_path, Atom(type, data_size, data)); } else if (!strcmp(types, "isisb")) { // blob (event), specific voice const char* type = &argv[3]->s; lo_blob b = argv[4]; size_t data_size = lo_blob_datasize(b); void* data = lo_blob_dataptr(b); set_voice_value(port_path, argv[2]->i, Atom(type, data_size, data)); } else if (!strcmp(types, "issN")) { // empty event (type only), all voices const char* type = &argv[2]->s; set_port_value(port_path, Atom(type, 0, NULL)); } else if (!strcmp(types, "isisN")) { // empty event (type only), specific voice const char* type = &argv[3]->s; set_voice_value(port_path, argv[2]->i, Atom(type, 0, NULL)); } else { return 1; } return 0; } /** \page engine_osc_namespace *\b /ingen/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::_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 uint8_t note_num = argv[2]->i; const uint8_t velocity = argv[3]->i; */ cerr << "FIXME: OSC note on\n"; //note_on(node_path, note_num, velocity); return 0; } /** \page engine_osc_namespace *\b /ingen/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::_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 uint8_t note_num = argv[2]->i; */ cerr << "FIXME: OSC note off\n"; //note_off(patch_path, note_num); return 0; } /** \page engine_osc_namespace *\b /ingen/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::_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 /ingen/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::_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; } /** \page engine_osc_namespace *\b /ingen/set_variable - Set a variable, associated with a synth-space object (node, etc) * \arg \b response-id (integer) * \arg \b object-path (string) - Full path of object to associate variable with * \arg \b key (string) - Key (index/predicate/ID) for new variable * \arg \b value (string) - Value of new variable
\n \n */ int OSCEngineReceiver::_variable_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { if (argc != 4 || types[0] != 'i' || types[1] != 's' || types[2] != 's') return 1; const char* object_path = &argv[1]->s; const char* key = &argv[2]->s; Raul::Atom value = Raul::AtomLiblo::lo_arg_to_atom(types[3], argv[3]); set_variable(object_path, key, value); return 0; } /** \page engine_osc_namespace *\b /ingen/set_property - Set an (RDF) property, associated with a synth-space object (node, etc) * \arg \b response-id (integer) * \arg \b object-path (string) - Full path of object to associate variable with * \arg \b key (string) - URI/QName for predicate of this property (e.g. "ingen:enabled") * \arg \b value (string) - Value of property
\n \n */ int OSCEngineReceiver::_property_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { if (argc != 4 || types[0] != 'i' || types[1] != 's' || types[2] != 's') return 1; const char* object_path = &argv[1]->s; const char* key = &argv[2]->s; Raul::Atom value = Raul::AtomLiblo::lo_arg_to_atom(types[3], argv[3]); set_property(object_path, key, value); return 0; } /** \page engine_osc_namespace *\b /ingen/request_variable - Requests the engine send a piece of variable, associated with a synth-space object (node, etc) * \arg \b response-id (integer) * \arg \b object-path (string) - Full path of object variable is associated with * \arg \b key (string) - Key (index) for piece of variable * * \li Reply will be sent to client registered with the source address of this message.
\n \n */ int OSCEngineReceiver::_variable_get_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* object_path = &argv[1]->s; const char* key = &argv[2]->s; request_variable(object_path, key); return 0; } /** \page engine_osc_namespace *\b /ingen/request_plugin - 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::_request_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* uri = &argv[1]->s; request_plugin(uri); return 0; } /** \page engine_osc_namespace *\b /ingen/request_object - 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::_request_object_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* object_path = &argv[1]->s; request_object(object_path); return 0; } /** \page engine_osc_namespace *\b /ingen/request_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::_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; } /** \page engine_osc_namespace *\b /ingen/request_plugins - Requests the engine send a list of all known plugins. * \arg \b response-id (integer) \n\n * \li Reply will be sent to client registered with the source address of this message.
\n\n */ int OSCEngineReceiver::_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 /ingen/request_all_objects - Requests the engine send information about \em all objects (patches, nodes, etc) * \arg \b response-id (integer)\n\n * \li Reply will be sent to client registered with the source address of this message.
\n \n */ int OSCEngineReceiver::_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { request_all_objects(); return 0; } // 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 (%s)\t", path, types); for (int i=0; i < argc; ++i) { lo_arg_pp(lo_type(types[i]), argv[i]); printf("\t"); } 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); OSCClientSender(url).error(error_msg); return 0; } } // namespace Ingen extern "C" { Ingen::OSCEngineReceiver* new_osc_receiver(Ingen::Engine& engine, size_t queue_size, uint16_t port) { return new Ingen::OSCEngineReceiver(engine, queue_size, port); } } // extern "C"