The concept of SwingOSC is mainly to map the API of the Java reflection mechanism to OpenSoundControl. Reflection means that although Java code is compiled (just in time), objects can inspect themselves, their methods and fields – just as in an interpreted language. This powerfull mechanism provides the basis for "scripting" java, that is, creating objects on the fly and calling arbitrary methods in an interpreted style.
Java distinguishes between fields and methods. To read a java object's field, the "/field"
and "/fieldr"
OSC commands are provided. To call a java object's method, the "/method"
and "/methodr"
OSC commands are provided. To instantiate an object, use the "/new"
command.
A variable mechanism is provided by the "/local"
, "/global"
and "/free"
OSC commands. Variables are referred to by an arbitrary identifier, similiar to node IDs in SuperCollider, however in SwingOSC an identifier can be a string as well. Unlike SuperCollider, variables (node IDs) are not linked in any kind of tree structure. Freeing a variable will not dispose or cleanup the object that it refers to; the client is responsible for calling appropriate methods before removing the variable.
Communication back to the client is accomplished by the "/query"
command. However, java classes themselves can provide other mechanisms, as demonstrated for example in the ActionResponder
class which uses a custom OSC message "/action"
.
Message formatting is closely based upon the perspective and features of SuperCollider's OSC engine. The key concepts are:
"/myWindow/contentPane/firstContainer/firstGadget/resize"
. Instead, each object is referred to by an identifier chosen by the client.( ... )
LISP-expression which gets evaluated to a single return value (with possible side-effects!). Sub-messages are evaluated from left to right in depth-first-order. If a sub-message has a return value, this value is used instead of the message as the argument of the outer message. For example, processing the message[ "/print", "[", "/local", "myPoint", "[", "/new", "java.awt.geom.Point2D$Double", "[", "/method", "java.lang.Math", "cos", 0.5, "]", "[", "/method", "java.lang.Math", "sin", 0.5, "]", "]", "]" ]
"/print"
command whose first argument is expected to be a variable name. Instead of writing the variable name as a string, we use a nested message that as a side effect calculates the cosine and sine of 0.5, creates a point object with these values and assigns that point object to a local variable myPoint
. "/local"
not only assigns a value to a variable but also returns the name of the variable, hence this name is the argument passed to "/print"
. Complicated?"[", "/ref", "brko", "]"
(open bracket) and "[", "/ref", "brkc", "]"
(close bracket).
To ease the use of Swing GUI classes and the Beans terminology, the "/set"
and "/get"
commands are provided.
By convention, SuperCollider notation is used in this reference document. That is, an OSC message is written as an array in square brackets [ ... ]
with the first element being the command name (or "OSC address") and the successive elements being the OSC message arguments. For brevity, method and variable names are sometimes written as symbols using a backslash (\myVariable
), although they are converted into strings by SuperCollider when sending the message. Placeholders are written inside pointed brackets < >
and prefixed by a javaish type name (Object
meaning "any kind of type"). When arguments can occur once or more, the notation [ ... ] * N
is used where the square brackets are not to be confused with a nested message!
Global assignments are assignments accessible by all clients. They share the same name space. Assigning an object to a global variable which already exists, will override that variable. This behaviour might change in the future, so be sure to free variables properly before reusing them. To distinguish variables from class names in a "/method"
statement, please do not use period characters in the variable name and do not begin with an uppercase character.
Syntax:
[ "/global" [ String <objectID>, Object <value> ] * N ]
Returns: the object identifier of the last assignment.
Example: [ "/global", "pi", 3.1415926 ]
Local assignments are assignments accessible only by the client which created that assignment. The client is identified by its sending address. Assigning an object to a local variable will obscure a global variable of the same name. To distinguish variables from class names in a "/method"
statement, please do not use period characters in the variable name and do not begin with an uppercase character.
Syntax:
[ "/local" [ String <objectID>, Object <value> ] * N ]
Returns: the object identifier of the last assignment.
Example: [ "/local", "pi", 3.1415926 ]
Each <objectID>
will be first looked up in the local dictionary, and, if not found, in the global dictionary.
Syntax:
[ "/free" [ String <objectID> ] * N ]
Returns: the value corresponding to the last freed object.
Example: [ "/free", "pi" ]
The values of variables are printed to the console of the SwingOSC server, using each object's toString()
method.
Syntax:
[ "/print" [ String <objectID> ] * N ]
Returns: the value corresponding to the last printed object.
Example: [ "/print", "pi" ]
This de-references an object and makes it available as an argument to a method call for example, by replacing the variable name with the variable value.
Syntax:
[ "/ref" String <objectID> ]
Returns: the value corresponding to the variable referred to by <objectID>
.
Example: [ "/global", "second_pi", "[", "/ref", "pi", "]" ]
Syntax:
[ "/array" [ Object <anObject> ] * N ]
Returns: an Object[]
array with elements provided by the arguments.
Example: [ "/new", "javax.swing.JComboBox", [ "/array", "spring", "summer", "autumn", "icecream" ]];
Typed arrays and arrays of primitives are not supported. Arrays always appear as Object[]
. This means that a method whose signature is for example public void theMethod( float[] someValues )
cannot be called. You may of course add a custom java class with a helper method public void theMethod( Object[] someValues )
that converts the arguments to a float array and calls the original method.
Syntax:
[ "/new" String <className>, [ Object <constructorArgument> ] * N ]
Returns: the newly created java object.
Example:
[ "/new", "javax.swing.JFrame", "MyTitle" ]
[ "/global", "myFrame", [ "/new", "javax.swing.JFrame", "MyTitle" ]]
Syntax:
[ "/method" String <objectID>, String <methodName>, [ Object <methodArgument> ] * N ]
Returns: the method return value or null
if the method has no return value (is declared void
).
Example:
[ "/method", "myFrame", "add", [ "/ref", "myButton" ]]
[ "/method", "myFrame", "toFront" ]
Note: when <objectID>
is the name of a class, the static class method will be invoked on that class.
e.g. [ "/query, "now", [ "/method", "java.lang.System", "currentTimeMillis" ]]
Syntax:
[ "/methodr" Object <anObject>, String <methodName>, [ Object <methodArgument> ] * N ]
Returns: the method return value or null
if the method has no return value (is declared void
).
Example: [ "/methodr", [ "/new", "java.awt.FileDialog", [ "/ref", \myFrame ]], \show ]
.
This is a helper mechanism which can be fully emulated using the /method
command. It is provided for improved readability and as a shortcut to /method
, similar to the <properties>
tag in java's XMLEncoder
.
Syntax:
[ "/set" String <objectID>, [ String <propertyName>, Object <propertyValue> ] * N ]
Returns: the return value of the last setter method or null
if that method has no return value.
Example:
[ "/set", "myButton", "focusable", false, "background",
[ "/new", "java.awt.Color", 0xFF, 0x00, 0x7F ]]
which is equal to
[[ "/method", "myButton", "setFocusable", true" ], [ "/method", "myButton", "setBackground", [ "/new", "java.awt.Color", 0xFF, 0x00, 0x7F ]]]
This method sends java objects back to the OSC client using "/info"
reply messages. These objects must be basic single value objects such as a string, a number, a boolean.
Syntax:
[ "/query" [ String <identifier>, Object <anObject> ] * N ]
Returns: the return value of the last getter method or null
if that method has no return value. Note that because of the "side-effect" nature of "/query"
, it shouldn't really be used in message nesting.
Example: [ "/query", "pi", [ "/ref", "pi" ], "second_pi", [ "/ref", "second_pi" ]]
This example will reply to the OSC client with the message [ "/info", "pi", 3.14..., "second_pi", 3.14... ]
Example: [ "/query", "piInt", [ "/method", "pi", "intValue" ],
"butSel", [ "/method", "myButton", "isSelected" ]]
This example will reply with the message [ "/info", "piInt", 3, "butSel", true ]
. So generally, the <identifier>
can be chosen arbitrarily by the client and is only used to let the client identity its query by looking at the even indices arguments of the "/info"
message.
This method sends object properties back to the OSC client using "/set"
reply messages.
As "/set"
is a shortcut for "/method"
, "/get"
is a shortcut for "/query"
. Property-getter methods are resolved by prepending "get"
to the property name in the first place, and, if not found, retrying with the prefix "is"
. Therefore a property "selected"
is looked up as method "getSelected()"
first, and, if not found, as "isSelected()"
second. Getter methods requiring additional argument must be invoked using the "/query"
command.
Syntax:
[ "/get" String <objectID>, [ String <propertyName> ] * N ]
Returns: the return value of the last getter method or null
if that method has no return value. Note that because of the "side-effect" nature of "/get"
, it shouldn't really be used in message nesting.
Example: [ "/get", "myButton", "selected", "focusable", "text" ]
This example will reply to the OSC client with the message
[ "/set", "myButton", "selected", true, "focusable", false, "text", "OK" ]
Syntax:
[ "/field" String <objectID>, String <fieldName> ]
Returns: the value of the field of the object saved in the variable <objectID>
.
Example:
[ "/field", "myDimension", "width" ]
[ "/field", "java.awt.Color", "red" ]
Note (second example): when <objectID>
is the name of a class, the static class field will be retrieved.
Syntax:
[ "/fieldr" Object <anObject>, String <fieldName> ]
Returns: the value of the field of the object <anObject>
.
Example: [ "/fieldr", [ "/new", "java.awt.Dimension", 320, 240 ], "width" ]
.
This allows you to dynamically expand the class path. You can add .jar
files or folders or single class files to the class loader's list of places to look for classes when a /new
command is executed. The places have to be specified as valid URLs. This way you do not need to add all places to java's class path when launching SwingOSC. It also allows you to add remote classes in a network.
Syntax:
[ "/classes" "add" [ String <classPathURL> ] * N ]
Returns: nothing
Example:
[ "/classes", "add", "file:///Users/rutz/Desktop/JCollider/build/JCollider.jar" ]
[ "/classes", "add", "http://java.sun.com/applets/other/Bubbles/Bubbles.jar" ]
[ "/classes", "add", "http://java.sun.com/applets/other/Bubbles/classes/Bubbles.class" ]
To remove or re-load modified classes use these signatures:
[ "/classes" "remove" | "update" [ String <classPathURL> ] * N ]
Syntax:
Turns on/off printing of incoming OSC messages to the console. The modes are 0 = no printing, 1 = text dump, 2 = hex dump, 3 = text + hex dump . the optional second mode toggles OSC dumping of outgoing messages.
Syntax:
[ "/dumpOSC" int <mode>, [int <mode2>] ]
Returns: nothing
Quits the server program.
Syntax:
[ "/quit" ]
Returns: nothing
Apart from local and global variables, a few constants are supplied by SwingOSC which can be addressed in the same way (using "/ref"
). These are:
\null
: the java null
reference. Note that due to a bug you cannot use this in a constructor ("/new"
) statement, for example (FIXED?) [ "/new", "javax.swing.JPanel", [ "/ref", \null ]]
don't seem to work. As a workaround you can do this: [ "/set", [ "/local", \myPanel, [ "/new", "javax.swing.JPanel" ]], \layout, [ "/ref", \null ]]
As of version 0.3, SwingOSC uses only core type tags when sending messages: i
(integer), f
(float), s
(symbol), b
(blob). However, when receiving, it should be able to decode 64-bit numbers as well as symbols and booleans. Time tags are ignored at the moment. This may change in the future, so it is advised to use the special time-tag nil
(scheduled for immediate execution) when creating bundles.
Since some OSC clients (i.e. SuperCollider) only have the core set of OSC type tags, some types are converted on the fly.
Also note that you can use the java wrapper classes for primitives. E.g.
[ "/new", "java.lang.Boolean", "true" ]
...although that looks a bit tedious
All commands are deferred to the Java AWT/Swing thread. Therefore, any GUI methods may safely be invoked. Note that messages are processed synchronously which means that time consuming method calls will block successive OSC commands until the method returns. In certain cases you may wish to use a special Java class that spawns a separate thread. The OSC receiver is running asynchronously, so messages arriving while a method is evaluated are safely cached, with memory only limited by the java VM stack size.
"/array"
for details.commands recognized by the server:
/array
: Constructing an Array Argument/classes
: Adding Classes/dumpOSC
: Debugging/field
: Retrieving Fields on Object References/fieldr
: Retrieving Fields directly/free
: Removing Assignments/get
: Getting Object Properties/global
: Creating a Global Assignment/local
: Creating a Local Assignment/method
: Calling Methods on Object References/methodr
: Calling Methods directly/new
: Creating an Object/print
: Printing Variables/query
: Getting Return Values/quit
: Terminating SwingOSC/ref
: Referring to an Assignment/set
: Setting Object Propertiescommands sent by the server in reply (DOCUMENTATION PENDING):
class specific reply commands (DOCUMENTATION PENDING):
last mod: 30-jul-07 sciss