Open Sound Control (OSC for short) is a network protocol that's emerged as the dominant over-ethernet wire-random-things-together protocol. Originally developed as a modern successor to MIDI in the music software realm, today all manner of outward-looking applications and devices read and write OSC.
Because of this popularity using OSC in Field is already extremely straightforward — just take your pick of Java-based or Pure-Python based OSC libraries, tell Field where they are located and then start writing code that uses them. But because of its importance as the glue that links interesting environments, and because Field is all about gluing things together, we've added a simple Field-ish OSC Plugin to the standard Field distribution. You are of course free to ignore the plugin and continue using your own OSC library.
If you don't have something that you want to send OSC to or from this page is probably not for you yet.
The plugin is called osc.mf
in the development tree (and will be osc.jar
in beta8). Turn it on in plugin manager.
The OSC Plugin creates a couple of new properties that are available to your code. The first of interest is OSCOut
. This lets you write:
_self.OSCOut.send("/banana/apple", (1, "peach", 3.2))
That sends a message "to" /banana/apple
containing an integer 1
, a string "peach"
and a floating point number 3.2
. Pretty straightforward, no?
This means that:
sheetSlider("banana", 0, update=lambda x : _self.OSCOut.send("/banana", (x, )))
Gets you a slider that sends a floating point number between 0 and 1 to "/banana":
Since OSC is (typically) an ethernet based protocol, OSC Plugin actually needs a port number and an address to send things to. Field defaults to an output port of 5501 and an address of "255.255.255.255" — this is the broadcast address, everybody on your sub-net will get these messages. This is typically the kind of low configuration overhead that you want.
To change the port and the address, use:
#changes the port to 11321
_self.OSCOut(11321).send("/banana/apple", (1, "peach", 3.2))
#changes the port to 11321 and the address to 18.85.9.1
_self.OSCOut(11321, "18.85.9.1").send("/banana/apple", (1, "peach", 3.2))
To change the default port and address, use the "-defaultOutputPort" and "-defaultAddress" command line options
Receiving OSC Messages in Field is, necessarily, a little more involved. It's one thing to tell some application or device what to do; it's quite another to be told what to do. Three vital lines of code get to receiving OSC messages in Field.
Firstly, tell Field that you want to receive an a box:
_self.OSCIn.dispatchOver(_self)
Whatever box you execute this in will be added to a list of visual elements that can respond to OSC events. Just as in the case of OSCOut
you can make a custom input by appending a port number (for example _self.OSCIn(10312).dispatchOver(_self)
) or by setting the startup option -defaultInputPort. Otherwise Field defaults to an input port of 5500.
Next, you have to tell Field what code you actually want to run when the OSC event comes in. Following on from other event callbacks (for example mouse handling in the Processing Plugin), we'll use Python Decorators.
@_self.handleOSC_
def myCallback(address, *args):
print address, args
Nothing happens — no callbacks are called — even though Field is receiving messages until you call _self.OSCIn.update()
— this is to give you're code ultimate control over whether and when the callbacks happen.
Typically, you'll want to call _self.OSCIn.update()
a lot, so the simplest thing is to just write:
def doOSCUpdate():
_self.OSCIn.update()
_r = doOSCUpdate
Start this code in a new box using option click or command-PgUp /command-PgDown (see VisualElementLifecycles).
That's all you really need to know to receive OSC messages inside Field.
So far there's nothing here that isn't included in a standard OSC library (although we hope the way that callbacks get set and called is a little tighter than a typical Java-based OSC library).
One extension to Field's OSC library is that the message hierarchy of OSC and the dispatch hierarchy of Field are integrated. Specifically, if you write
_self.OSCIn.dispatchOver(_self)
in some visual element that has a subelement
called "banana" then all messages that start /banana
get routed to that box instead — that is, only callbacks registered there will get called.
Matching proceeds as far down the visual element graph as possible. So if you have a box called "pear" that delegates to "banana" that delegates to the element that you designated as a message root with .dispatchOver
then the address "/banana/pear" sends messages to only callbacks in that box. "/banana/*" sends messages to all callbacks in all children of "/banana" and so on.
This marries OSC's idea of modular routing to Field's.
Field's OSC plugin is very new (although the underlying OSC code is very old, very tested and very straightforward) — expect bugs, but OpenEnded are working on projects that use this code, so expect a fast response to bug reports.
Functionality wise, it is currently lacking a complete set of OSC data-types — it handles integers, strings and floats and nothing more. We've never encountered much more than these things in real life, but it's easy to add more types. It's also lacking an idea of input message coalescing — if you take a long time between calls to .update()
you'll always get all of the messages sent in the intervening interval. This is sometimes what you want, but not always.