OSC Messages¶
Many people have been using message passing not only to control Max/PD objects, but also to interact with processes living outside MAX/PD such as CSound, SuperCollider, etc.
To make their life easier, Antescofo comes with a builtin OSC server. The OSC protocol can be used to interact with external processes using UDP messages. It can also be used to make two Antescofo objects interact within the same patch or even used internally to a single Antescofo object (the program emitting messages to itself).
The management of OSC messages is achieved in Antescofo through 3 primitives.
OSCSEND¶
This keyword introduces the declaration of a named OSC output channel of communication. The declaration takes the form:
oscsend name host : port msg_prefix
where:
-
name
is a simple identifier or an expression (which evaluates to a string). and refers to the output channel (used later to send messages). -
host
is the optional IP address (in the formnn.nn.nn.nn
wherenn
is an integer) or the symbolic name of the host (in the form of a simple identifierlocalhost
or an expression returning a string (like "test.ircam.fr"). If this argument is not provided, the localhost (that is, IP 127.0.0.1) is assumed. -
port
is an expression defining the mandatory number of the port where the message is routed (e.g. between 49152 and 65535, see List of TCP and UDP port numbers). -
msg_prefix
is the OSC address in the form of a string that will prefix the OSC message send to this channel.
All these parameters can be expressions that are evaluated dynamically
when the oscscsend
action is executed.
As soon as the OSC channel is declared, it is started and can be used to send messages. Note that sending a message before the definition of the corresponding output channel is interpreted as sending a message to MAX.
Sending OSC messages¶
Sending an OSC message takes a form similar to sending a message to MAX or PD:
name arg₁ arg₂ ...
This action construct and send the osc message
msg_prefix arg₁ arg₂ ...
where msg_prefix
is the OSC address declared for name
. Note that to
handle different message prefixes, different output channels have to be
declared.
The character /
is accepted in an identifier, so the usual
hierarchical name used in OSC message prefixes can be used to identify
the output channels. For instance, the declarations:
oscsend extprocess/start test.ircam.fr : 3245 "start" oscsend extprocess/stop test.ircam.fr : 3245 "stop"
can be used to later invoke
0.0 extprocess/start "filter1" 1.5 extprocess/stop "filter1"
Notice that if the oscsend name is the result of a complex computation, then the @command construction must be used to refer to the command name. For example :
$host := @compute_some_machine_name(...) $name := "reverb_" + $host + "--" + $port oscsend $name $host : $port "/reverb" ; ... @command($name) 10 reverb_mac1--34567 14 reverb_mac2--34567 18
Notice the oscsend name is not part of an osc message, it is simply the
identifier used internally to the Antescofo programm to refer to an
external address. In the previous example, a name is forged because it
is explicitly used through known identifier reverb_mac1--34567
and reverb_mac2--34567
in the
program. It can also be refered trough a computation as in @command($name)
.
Scope of OSC sending command¶
OscSend
action creates a new name to send osc
messages. This name follows the scoping
rules used for
variables and the hierarchy of execs: it can be used in the current
exec and its children, unless hidden by a new oscsend definition.
This means that the same identifier can refer to different delivery addresses. This is especially usefull for object and processes : the name given to an oscsend command in a process instance always refers to the delivery addresse computed in the process instance, even if the same name is used for all instances.
At the termination (including all its children) of the exec of definition of the OSC command, the corresponding network resources are released.
Here is an example :
forall $cpt in (10) { oscsend ping "webservice.ircam.fr" : (34560+$cpt) "/ping" ::P() }
Withing ::P
the command ping
can be used
to send an osc message (even if the corresponding oscsend is not in
scope of ::P
but in an enclosing scope).
The destination of the message depends on the process instance: the
ith instance refers to the port 34560+i on the host
"webservice.ircam.fr" because of the oscsend command in the forall
body. The network resources allocated to reach this host are released
when the corresponding instance of ::P
die.
Interpretation of message receivers as OSC or Max/PD or file receivers¶
The definition of an oscsend name id prohibits sending Max/PD message to receivers with the same identifier id in the scope of the oscsend action. As a matter of fact, the three constructions:
-
sending an osc message,
-
sending a Max/PD message,
-
and writing in a file
share the same syntax. Antescofo uses the message identifier to known which construction is used. Max receivers are not predefined, contrary to osc messages: receivers are declared with the oscsend command and output files are declared using the [openout] construction. The handling of messages first looks for an osc receivers taking the scope into account. If there is no such receivers, a receiver for writing in a file is searched. Finally, if there is no such receivers, the message is handled as a message for Max or PD.
The previous example (involving a process) outlines that looking for OSC name is a dynamic process nt a syntactic one. this makes possible to write generic procedure whose messages get their actual interpretation following the context of execution.
Refering to multiple addresses¶
The oscsend action accepts the specification of a list of destination. Each message sent with the oscsend name is sent to all the addresses, achieving a (poor) kind of multicast:
oscsend send2m "m1.ircam.fr" : 34567 "/antescofo/cmd", \ "m2.ircam.fr" : 34567 "/antescofo/cmd", \ "m3.ircam.fr" : 34567 "/antescofo/cmd", \ "m4.ircam.fr" : 34567 "/antescofo/cmd"
with this declaration, a message
send2m arg₁ arg₂ ...
will send the data arg₁ arg₂ ...
to four hosts simultaneously (the backslash at the end of the line is
simply used to break the long definition on multiple lines).
In addition, further oscsend
commands with the same
name, simply add the specified addresses to the target of the
message. So
oscsend send2m "m1.ircam.fr" : 34567 "/antescofo/cmd" send2m 1 ; ... oscsend send2m "m2.ircam.fr" : 34567 "/antescofo/cmd" ; send2m 2
will send 1
to host m1.ircam.fr
and later will send the
value 2
to hosts m1.ircam.fr
and m2.ircam.fr
. The
lifetime of the target addresses depends of the scope of the oscsend
command used to add the address.
Sending several messages with one receiver¶
Sending an osc message accept the comma syntax used for sending simultaenously several messages to the same Max/PD receiver:
oscsend send : 345678 "/header" ; ... send 1 2 3, 4 5 6, 7 8 9
will send three messages to the osc receiver send
.
More generally the constraints of Max/PD messages apply on OSC messages (a message must fit on one line or backslash are explicitly used to break the message on multiple line; osc message accept the same attributes as Max/PD message, etc.).
OSCRECEIVE¶
This keyword introduces the declaration of an input channel of communication. The declaration takes the form:
oscrecv name port msg_prefix $v₁ $v₂ ...
where:
-
name
is the identifier of the input channel and is used later to stop explcitly the channel. -
port
is the mandatory port number where the is received. -
On the previous port, the channel accepts messages with OSC address
msg_prefix
. Note that for a given input channel, the message prefixes have to be all different. -
When an OSC message is received, the argument are automatically assigned to the variables
$v₁
,$v₂
... If there is less variables than arguments, the remaining arguments are simply thrown away (and an error message is emitted). Otherwise, if there is less arguments than variables, the remaining variables are set to undef (and an error message is emitted).
The name
, port
and msg_prefix
parameters can be expression which
must return string, integer and string respectively.
Currently, Antescofo accepts only the following OSC types: bool, int32, int64, float, double, string and the arrays markers bracketing sequence of these values (nested arrays are allowed). These value are converted respectively into boolean, integer, float, string and bracketed sequence are converted into tab.
A Whenever can be used to react to the reception of an OSC message: it
is enough to put one of the variables $vᵢ
as the condition of the
whenever.
So, a typical handling of OSC incomming messages takes the following form:
oscrecv receive_command 34567 "/cmd" $cmd $arg whenever ($cmd) { ; process $arg following $cmd }
refers to teh whenever compound action to have a complete description of this mechanism.
Dispatching Incomming Messages¶
Notice that message header msg_prefix
is part of an oscrecv
declaration. It means that OSC messages with different prefixes
can be sent to the same port andd are handled in the antescofo program
with different oscrecv actions:
oscrecv receive_command 34567 "/cmd" $cmd $arg whenever EvalCommand ($cmd) { ; process $arg following $cmd } oscrecv abort_command 34567 "/abort" $abort whenever ($abort) { abort EvalCommand }
Here, messages corresponding to comamd are sent to the port 34567
with a /cmd
prefix while an abort control command is sent to the same
port with the prefix /abort
.
OSC messges have the same constraint as Max/PD messages : they cannot be
empty. So the variable $abort
is a ummy variable used
soelly for triggering the whenever (that abort the other whenever used
to handle command).
Scope of an OscRecv¶
The reception is active as soon as the input channel is declared. The listening process is terminated as soon as one of the variable declared in the oscrecv command becomes inaccessible.
Local variables can be used in an oscrecv declaration, e.g. in a proc or in an obj. Together with the possibility to compute the parameters of the reception, it makes possible to write generic obj to handle incomming osc message.
OSCOFF¶
This commands take the name of an input channel or an output channel. This command is used to stop earlier the osc facilities bound to an osc name and to release earlier the associated network resources.
Such actions are sometimes needed,e.g. when it is convenient to associate the reception of osc messages to global variables but where the period of receptions is smaller than the entire piece.
Conversion between OSC types and Antescofo types¶
Sending (or receiving) an OSC message implies the conversion of an Antescofo value into an OSC value (or the reverse). The conversion is applied following the following mapping
Antescofo value | OSC value |
---|---|
bool | bool |
int | int32 see function @set_osc_handling_int64 |
int | int64 see function @set_osc_handling_int64 |
Float | float see function @set_osc_handling_double |
Float | double see function @set_osc_handling_double |
string | string |
string | symbol |
tab | see function @set_osc_handling_tab |
Remarks
-
Antescofo value types that are not present in the table are not handled (e.g. proc or nim).
-
The default handling of Antescofo integers is to send them as 32 bits integers, the only precision required by the OSC protocol. A call to
@set_osc_handling_int64(true)
switches this default behavior to send 64 bits integers instead. Notice that this feature is not implemented in all OSC packages. See function @set_osc_handling_int64. -
The default handling of Antescofo float is to sending them as floats (32 bits representation), the precision required by the OSC protocol. A call to
@set_osc_handling_double(true)
switches this default behavior to send double (64 bits representation) instead. Notice that this feature is not implemented in all OSC packages. See function @set_osc_handling_double. -
The handling of tab can be changed using the @set_osc_handling_tab functions. By default, Antescofo sends the elements of a tab as the successive arguments of a message, without using the OSC array facilities. A call to
@set_osc_handling_tab(true)
switches the behavior to rely on the array feature present in OSC v1.1. A call to@set_osc_handling_tab(false)
switches to the default behavior (tab flattening).