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:

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
is simply a shorthand for
    @local $x
    $x := expr
The assignment is done at the right moment (for instance, the value of $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 nth 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 gnuplot1. 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 a NOTE 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 and RNOW 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


  1. 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.