Variables¶
Antescofo variables are imperative variables: they are like a box that holds a value. The assignment of a variable consists of changing the value stored in the box:
$v := expr
let $v := expr
The two forms are equivalent, but the let
keyword is
sometimes mandatory, see below. They are four shortcuts for assignments:
$v += expr ; is a shortcut for $v := $v + expr
$v -= expr ; is a shortcut for $v := $v - expr
$v *= expr ; is a shortcut for $v := $v * expr
$v /= expr ; is a shortcut for $v := $v / expr
An assignment is an action and like other actions, it can be done after a delay. We stress that variable assignments are actions and not expressions. However, they are instantaneous and they can appear in extended expressions in the body of a function.
Variables are named with a $
-identifier. By default, a variable is
global - that is, it can be referred to in an expression anywhere in a
score.
Note that variables are not typed: the same variable may hold and integer and later a string, for example.
User variables are assigned within an augmented score using Assignment Actions, see assignment. However, they can also be assigned by the external environment, using a dedicated API:
-
the reception of an OSC message,
-
the message setvar or the internal command antescofo::setvar,
-
the function @loadvar.
Also see the section accessing scoped variable below.
Histories: Accessing the Past Values of a Variable¶
Variables are managed in an imperative manner. The assignment of a
variable is seen as an internal event that occurs at some date. Such
event is associated to a logical instant. Each variable has a
time-stamped history. So, the value of a variable at a given date can be
recovered from the history, achieving the notion of stream of values.
Thus, $v
corresponds to the last value (or the current
value) of the stream. It is possible to access the value of a variable
at some date in the past using the dated access:
[date]:$v
returns the value of variable $v
at date date
. The date can be expressed in three different ways:
-
as an update count: for instance, expression
[2#]:$v
returns then antepenultimate value of the stream; -
as an absolute date: expression
[3s]:$v
returns the value of$v
three seconds ago; -
and as a relative date: expression
[2.5]:$v
returns the value of$v
2.5 beats ago.
For each variable, the programmer may specify the size n of its history variable declaration. So, only the n “last values” of the variable are recorded. Accessing the value of a variable beyond the recorded values returns an undefined value.
Dates functions¶
Two functions let the composer to know the date of a logical instant associated to the assignment of a variable:
@date([n#]:$v)
returns the date in absolute time of the nth to the last assignement of and
@rdate([n#]:$v)
returns the date in relative time (relative to the musician).
These forms mimic the form of functions but they are not; they are special forms and only accept a variable or the dated access to a variable.
Variable Declaration¶
Variables are global by default, that is, visible everywhere in the score, or they are declared local to a sequence of actions which limits its scope and puts a constraint on its lifetime.
For instance, the scope of a variable declared local in a loop
body is restricted to one instance of the loop body, so two loop
bodies refer to two different instances of the local variable. This is
also the case for the body of a whenever or of a process.
Local Variables¶
To make a variable local to a scope, it must be explicitly declared using a @local declaration. A scope is introduced for the body of each compound action. The declaration, may appear everywhere in the scope and takes a comma separated list of variables:
@local $a, $i, $j, $k
There can be several declarations in the same scope and all local variables can be accessed from the beginning of the scope, regardless of the location of their declaration.
A local variable may hide a global variable and there is no warning if it does. A local variable can be accessed only within its scope. For instance
$x := 1
group {
@local $x
$x := 2
print "local var $x: " $x
}
print "global var $x: " $x
will print
local var $x: 2
global var $x: 1
Initialization of variables¶
The decalarations @global
and @local
can
be used to give an initial value to the introduced variables :
@global $x := 0, $y := 0
group {
@local $u := 3 + $x, $v := $u, $w := 0
$x := 3
@local $z := $x + $u
; ...
}
The order of initialization matters. They are two kinds of
initialization depending on the expression e in the right hand side of
:=
.
If e is a constant expression, the value of the expression is computed at parsing time and becomes the initial value of the variable.
If e is not a constant expression, then the declaration
@local $x := e
@local $x
$x := expr
$z
in the previous example is 6
).
This assignment eventually triggers a whenever if the variable is
watched.
Lifetime of a Variable¶
A local variable can be referred as soon as its nearest enclosing scope is started but it can persist beyond the enclosing scope lifetime. For instance, consider this example :
Group G
{
@local $x
2 Loop L
{
... $x ...
}
}
The loop L
nested in the group runs forever and accesses
the local variable after “the end” of the group G
(the
group ends whith the launch of its last action, see Action
Sequence). This use of
$x
is perfectly legal. Antescofo manages variables
efficiently and the memory allocated for $x
persists as
long as needed by the children of G
but no more.
History Length of a Variable¶
For each variable, Antescofo only records a history of limited size. This size is predetermined, when the score is loaded, as the maximum of the history sizes that appears statically in expressions and in variable declarations.
In a declaration, the specification of a history size for the variable takes the form:
n:$v
where n
is an integer. This syntax specifies that
variable has an history of length at least n
.
To make it possible to specify the size of global variable's history, there is a declaration @global
@global $x, 100:$y
similar to the declaration @local. Global variable declarations may appear anywhere an action may appear. Variables are global by default, thus, the sole purpose of a global declaration, beside documentation, is to specify history lengths.
The occurence of a variable in an expression is also used to determine
the length of its history. In an expression, the n
th past
value of a variable $v
is accessed using the dated
access construction (see above):
[n#]:$v
When n
is a constant integer, the length of the history is assumed to
be at least n
.
When there is no declaration and no dated access with constant integers, the history size has an implementation dependant default size.
The special form @history_length($x)
returns the
length of the history of the variable $x
.
History reflected in a Map or in a Tab¶
The history of a variable may be accessed also through a map or a tab. Three special functions are used to build a map (resp. a tab) from the history of a variable:
-
@map_history($x)
returns a map where key n refers to the n-1 to the last value of$x
. In other word, the element associated to 1 in the map is the current value, the previous value is associated to element 2, etc. The size of this list is the size of the variable history, see the paragraph History Length of a Variable below. However, if the number of updates to the variable is less than the history length, the corresponding undefined values are not recorded in the map. -
@tab_history($x)
is similar to the previous function but returns a tab where ith element refers to the the n-1 to the last value of$x
. -
@map_history_date($x)
returns a map where the value of key n is the date (physical time) of the n-1 to the last update of$x
. The previous remark on the map size applies here too. -
@tab_history_date($x)
builds a tab (instead of a map) of the dates in physical time of the of updates of the var$x
. -
@map_history_rdate($x)
returns a map where the value associated to key n is the relative date of n-1 to the last update of$x
. The previous remark on the map size applies here too. -
@tab_history_rdate($x)
builds a tab (instead of a map) of the dates in relative time of the updates of the var$x
.
These six functions are special forms: they only accept a variable as an argument. These functions build a snapshot of the history at the time they are called. Later, the same call will eventually build different maps and tabs. Beware that the history of a variable is managed as a ring buffer: when the buffer is full, any new update takes the place of the oldest value.
Plotting the history of a variable¶
The history of a variable can be plotted in absolute or in relative time
using the command @plot and @rplot. These two functions are special
forms accepting only a list of variables as arguments. They return
true
if the plot succeeded and false
elsewhere.
If there is only one argument $x
, the referred values
can be a tab (of numeric values) and each element in the history of the
tab is plotted as a time series on the same window. If they are more
than one argument, each variable must refer to a numeric value and the
time series of the variables values are plotted on the same window.
Note that only the values stored in the history are plotted : so usually one has to specify the length of the history to record, using a @global or @local declaration.
The @plot
and @rplot
special forms expand
to a call to the function gnuplot
1. For example,
the expression expands into
@gnuplot( "$x", @history_tab_date($x), @history_tab($x),
"$y", @history_tab_date($y), @history_tab($y) )
See description of @gnuplot in Library Functions.
Accessing a Local Variable “From Outside its Scope of Definition”¶
A local variable can be accessed in its scope of definition, or from one of its child scopes, using its identifier. It is possible to access the variable from “outside its scope” using the dot notation through an exec. Here, “outside” means “not in the scope of definition nor in one of its children”. Beware that accessing a local variable from outside its definition scope:
-
is correct only within the lifetime of the variable,
-
does not extend the lifetime of the variable which is still bound to the lifetime of its definition scope and its children.
If the scope of definition of the variable is not alive at the time of the access, an undefined value is returned and an error is signaled. Else, if there is no variable with this identifier locally defined in the scope, then the variable is looked up in the enclosing scope. The process is iterated until the top-level is reached. At this point, if there is no global variable with the specified identifier, an undefined value is returned and an error is signaled.
The Dot Notation¶
To access the variable defined in one specific instance of a group, or more generally of a compound action introducing a scope (@whenever, loop, process call, etc.), one must use the dot notation through the exec referring to this instance. Exec are introduced in section Exec.
It is possible to read the value of a local variable through the dot notation:
$p := ::P()
$x_of_p := $p.$x
Expression $p.$x
get the value of the local variable
$x
in the process ::P
launched at the
previous line. The instance of the process is accessed trough its
exec, see section Exe.
The expression at the left of the dot operator may be more complex than just a variable:
$p := [ ::P() | (10) ]
$x_of_p2 := $p[2].$x
The first line launch 10 instances of process ::P
using a
tab comprehension. The second line get the local variable of the third
instance of ::P
.
Assigning a Variable From Outside its Scope¶
As previously mentionned, a variable can be assigned from “outside”, see:
-
the reception of an OSC message OSCreceive,
-
the message setvar,
-
the function @loadvar,
-
the assignment using the dot notation.
The OSCreceive and the setvar command can be used only for global variable. But local variable can be the target of the two other mechanisms.
The assignment of a local variable through the dot notation is similar to an usual assignment:
$p := ::P()
let $p.$x := 33 // assign the local variable $x in the process ::P
The expression at the left of the dot operator may be more complex than just a variable:
$p := [ ::P() | (10) ]
let $p[2].$x := 33
The first line launches 10 instances of process ::P
. The
second line sets the local variable of the third instance of ::P
.
Notice the let
keyword: it is needed in an assignment
when the expression in the left hand side of the assignment is more
complex than a variable.
These assignments are monitored by the whenever where the local
variable $x
appears. But an expression $p.$x
does not monitor the local variable of the process. See section
Reference to a scoped
variable
Antescofo System Variables¶
System variables are internal variables managed directly by Antescofo and are updated automatically by the system. They are useful for interacting with, for example, the machine listener during performances and creating interactive setups.
The following variables are managed as ordinary variables:
-
$BEAT_POS
is the position in beat of the last detected event in the score. Due to grace notes (event with a zero duration), two distinct musical events can have the same beat position. -
$CURRENT_EVENT_INDEX
is the rank of the last detected event in the score. Contrary to
$BEAT_POS
, the value of$CURRENT_EVENT_INDEX
is different for each event. These two system variables are updated at each detection of a new musical event (detected by the listening machine as well as notified through a [nextevent] command). See also function @current_event. -
$DURATION
is the duration of the last detected event, as specified in the score. -
$ENERGY
is the current normalized energy of the audio signal from the listening machine. The returned value is always between 0.0 and 1.0 and is equivalent to the Calibration Output of the Antescofo object in Max and Pd. NOTE: The variable is updated with high frequency (equal to the analysis hop size). Use it with care inside processes and Whenever constructs. -
$LAST_EVENT_LABEL
is the label of the last event seen. This variable is updated only if the event has a label. -
$PITCH
is the pitch (in MIDI Cents) of the current event. This value is well defined in the case of aNOTE
and is not meaningful for the other kinds of event. -
$RT_TEMPO
represents the tempo currently inferred by the listening machine from the input audio stream. -
$SCORE_TEMPO
returns the tempo constant in the score at the exact score position where it is called.
-
$RCNOW
is the date in relative time (in beats) of the “current instant”. It can be interpreted as the current position in the score. This position is continuously updated between the occurence of two events as specified by the current tempo. Thus, if the next event occurs later than anticipated, the value of$RCNOW
will jump backward. The variable$RCNOW
represents the beat position of an action that is synchronized as@tight @progressive
-
$RNOW
is the date in relative time (in beats) of the “current instant”. It can be interpreted as the current position in the score. This position is continuously updated between two events as specified by the current tempo. But, contrary to$RCNOW
, the increase stops when the position in the score of the next expected event is reached andRNOW
is stuck until the occurrence of this event or the detection of a subsequent event (making this one missed). Thus, it does not decrease. The variable$RNOW
represents the beat position of an action that is synchronized as@tight
Note that when an event occurs, several system variables are likely to change simultaneously. Notice that, as for all variables, they are case-sensitive.
Special Variables¶
These variables are similar to system variables, but they cannot be watched by a whenever:
-
$NOW
corresponds to the absolute date of the “current instant” in seconds. The “current instant” is the instant at which the value of is required. -
$MYSELF
denotes the exec of the enclosing compound action. -
$THISOBJ
may appears in method definitions where it refers to the object on which the method is applied, or in the clauses of an object definition where it refers to the current instance.
Variables and Notifications¶
In Antescofo, a set of entities to be notified is associated to each variable. The notification mechanism is the core device used by the reactive engine to implement the computations.
Notification of events from the machine listening module drops down to
the more general case of variable-change notification from an external
environment. Actions associated to a musical event are notified through
the variable $BEAT_POS
. This is also the case for the
group
, loop
and curve
constructions which need the current position in the score to launch
their actions with @loose
synchronization strategy. The
whenever
construction is notified by all the variables
that appear in its condition. The scheduler must also be globally
notified upon any update of the tempo computed by the listening module
and on the update of variables appearing in the local tempi expressions.
Temporal Shortcuts. The notification of a variable change may trigger a computation that may end, directly or indirectly, in the assignment of the same variable. This is known as a “temporal shortcut” or a “non causal” computation. The reactive engine takes care of stopping the propagation when a cycle is detected. See section Causal Score and Temporal Shortcuts.
The next section temporal variables investigates the use of a variable to track a process and to infer a tempo. Then we take a look at
-
The
gnuplot
program is a portable command-line driven graphing utility for Linux, MS Windows, Mac OSX, and many other platforms. Cf. www.gnuplot.info. It must be installed on the system to have a working @gnuplot function. ↩