The `osc-clj` client allows you to send OSC messages to a server listening on a specific port on a specific host.
OSC messages contain the following elements:
* A path (i.e. `/foo/bar/baz`)
* An arbitrary list of params (i.e. `2 "baz" 3.14159265 (byte-array 10)`
The supported param types are:
You don't need to specify which type you are using, `osc-clj` will infer these with reflection.
Each message may or may not trigger a method handler to be executed on the receiving server - this is dependent on whether the path sent matches a registered handler on the server. Multiple handlers can be called by using regexp-like patterns in your out going path which may be matched to multiple handlers (see the pattern matching section below for more info).
#### Sending Messages
In order to send messages, you must first create a client withi `osc-client`:
(def client (osc-client "localhost" 9801))
Then you may send a message using `osc-send`:
(osc-send client "/foo/bar/baz 1 2 "three")
The `osc-clj` server allows you to receive OSC messages by listening on a specific port. You may then register method handlers and/or listeners with the server which may be triggered by incoming messages.
Create new server with `osc-server`:
(def server (osc-server 9800))
`osc-clj` servers support both listeners and handlers. Listeners are fns you register which will be triggered for each and every incoming message. The fn must accept one argument - the message to receive. Each listener may also be associated with a unique key which allows you to individually remove it at a later time.
Here we use `osc-listen` to add a generic listener that will print *all* incoming OSC messages to std-out. We also specify the key `:debug`:
(osc-listen server (fn [msg] (println "Listener: " msg)) :debug)
To remove the listener simply call:
(osc-rm-listener server :debug)
`osc-clj` also supplies the fn `osc-rm-all-listeners` which will remove all listeners on the specified server.
#### OSC Method Handlers
Handlers are registered with an OSC path such as /foo/bar - they are only triggered if the path of the incoming OSC message matches the registered path.
To register a handler for the path "/foo/bar" do the following:
(osc-handle s "/foo/bar" (fn [msg] (println "Handler for /foo/bar: " msg)) :foo)
This will only print out received messages that match the path "/foo/bar". To remove call:
(osc-rm-handler s "/foo/bar" :foo)
`osc-clj` also supplies the fns `osc-rm-handlers` which will remove all the server's handlers on the specified path and `osc-rm-all-handlers` which will remove all the servers handlers within the path and below in the hierarchy (i.e. `(osc-rm-all-handlers server "/foo")` will remove all handlers registered at /foo and any below i.e. /foo/bar /foo/bar/baz etc. Passing no path to `osc-rm-all-handlers` will remove *all* handlers on the server.
OSC bundles are groups of messages with a collective timestamp. This allows groups of messages to be scheduled to be handled at the same time which may be some arbitrary point in the future.
#### Receiving Bundles
When `osc-clj` receives a timestamped bundle it will schedule the bundle to be handled at the time of the timestamp. However, if the time is in the past, it will be handled immediately.
Handling the bundle means unpacking it and handling each contained message in sequence. Therefore, if a bundle contains another, and the inner bundle's timestamp is earlier than the outer bundle, it will *not* be honoured - instead it will trigger at the outer bundle's timestamp.
The simplest way to construct and send a bundle is with the macro `in-osc-bundle`. All OSC messages and bundles sent within the scope of the macro call will get sent together in the parent bundle with the specified timestamp:
Send the enclosing messages inside a bundle that is timestamped for 1 second from now: