The Macro Language

DM84 macros are simply a series of instructions - expressed using the DM84 macro language. The macro language is a set of building blocks from which different types of instructions can be formed. These building blocks, or language elements, are:

Macros may contain up to 64 "lines", each containing one or more instructions. Multiple instructions MUST be separated by a ';' (semicolon) character. Loop and conditional instructions may be combined. These maximum length of a line is 115 characters.

Macros are "run" in response to some triggering event, such as a serial command or the pressing of a pushbutton connected to a programmable logic input pin. Applications such as room combining, courtroom sound systems, and teleconferencing rely on macros to make system setup changes "on the fly" in response to button panel activity or serial commands from 3rd party control systems.

 

Commands

DM84 commands consist of:

For example:

The built-in command set of the DM84 is extensive, so the documentation is broken up into sections:

General Commands Audio Input Matrix Crosspoints Audio Output Input Compressor Output Compressor
Output Limiter Programmable I/O Front Panel Control Rear Panel Control ADFE System  

Special built-in commands for use in macros: Two built-in commands are of special interest:

Verbose mode commands in macros: If a "verbose mode" command is executed within a macro, the response will be sent back on the RS232 serial port, rather than suppressed. This can be useful for 3rd party control panel applications that rely on command responses to update their visual controls - they can stay synchronized with the device state when a macro is run. Verbose mode commands are those prefixed with the '!' (bang) character, for example: !ingn(3)=0

 

Variables

Variables are user defined, and consist of a variable "name" enclosed within a pair of '@' characters. The name may include any of the printable characters except '@'. The maximum length allowed for variable names is 15 characters (not including the enclosing '@' characters). Examples: @stage2@ or @mic_muted@. Variable names are case sensitive! For example, @foo@ is not the same variable as @Foo@ or @FOO@.

Variable types: Variables can store the following LecNet2 data "types":

Initializing variables: A variable is "initialized" the first time (after powerup) that the macro command processor encounters an instruction assigning a value to it. For instance, running a macro containing the instruction @foo@=42 will cause the variable @foo@ to be created if it doesn't already exist. The variable @foo@ is said to be "initialized" at this point with integer value 42. The instruction @bar@={1,2,3,4,5}, on the other hand, would initialize @bar@ with an array of integer value with 5 elements.Important: variables are "volatile", which means that they are lost when power is removed from the DM84. When the DM84 is powered back up, the variables will be initialized all over again as described above.

Array variable size: The maximum size of an array variable is 32 elements.

Accessing elements in array variables: Individual elements of a variable of type array of integer or array of boolean can be accessed using a "subscript" notation. For example, @foo@[2] accesses the 2nd element in the array. The location of the element MUST be a an integer value between 1 and 32 enclosed within a pair of '[' and ']' characters. The location may also be specified as a variable with an integer value, or even by an arithmetic expression. For example:

Important: It is an error to address array elements that don't exist, such as in @foo@[5], when @foo@ has only 4 elements. It is also an error to use the subscript notation with any variable whose type is not an array of integer or array of boolean (e.g. strings, simple integers).

Arithmetic with variables: Basic integer arithmetic operations may be performed using variables. Addition ('+'), subtraction ('-'), multiplication ('*'), division ('/') and modulo division ('%') operations are supported, but remember that the variable needs to hold an integer value for the result to make sense. Use pairs of parentheses, '(' and ')', to group terms in complicated expressions to get the proper result. The value of an arithmetic expression is the integer result of the operations. For example:

Comparison with variables: An integer variable can be compared to a literal integer value or another integer variable. A string variable can be compared to a another string variable, or tested for equality with a string literal. Equality ('== '), inequality ('!= '), less than ('<'), greater than('>'), less than or equal ('<= ') and greater thanor equal ('>= ') comparisons are supported. For string types the comparisons are"lexical" in nature - they are compared character by character, and characters are judged by their ASCII code value. So "aaa" is equal to "aaa" but not equal to "aaaa", and "abc" is "less than" "bbc" because 'a' comes before 'b' in the ASCII table. The value of a comparison expression is a boolean type: "true" if the condition is met or "false" if the condition is not met. For example:

Since an arithmetic expression has an integer value, it can substitute for an integer within a comparison expression. For example:

Note that the arithmetic expression MUST be enclosed with parentheses for this to work properly.

Logic with variables: Any variable with an integer value can be treated as a boolean type, either "true" or "false". The convention is that the integer value zero (0) means "false" and any nonzero value means "true". Variables that are used in this way can then be compared using the "logical" operations "AND" ('&&'), "OR" ('||') and "NOT" ('!'). The value of a logical expression is also a "boolean" type. For example:

Going further, more complicated expressions can be formed by grouping terms using parentheses to get the proper result. Also, since a comparison expression has a boolean value, it can substitute for a boolean variable within a logical expression. For example:

Note that the comparison expression MUST be enclosed with parentheses for this to work properly.

Assigning a value to a variable: A value can be assigned to a variable in several ways. Whatever the method, the assignment instruction begins with the variable name followed by the assignment operator '=', like this: @foo@=. Next comes the expression for the value to be stored in the variable. The possibilities are:

Variables as command arguments: Once variables are initialized, they can be directly assigned to some device property. For example:

First, initialize the variable in a macro:

@foo@={0,0,0,0}

and then somewhere else in the same macro, or in another macro...

outgn(*)=@foo@

The "argument" to the outgn command is now a variable name, rather than a literal integer array, such as {0,0,0,0}. Now the value of @foo@ can be controlled by one macro, and used by one or more other macros when setting the output gains. Variables can also be used within an integer array. For example:

First, initialize the variable in a macro:

@foo@=-3

and then somewhere else in the same macro, or in another macro...

outgn(*)={0,@foo@,0,0}

In this case the 2nd array element takes on the value of variable  @foo@. Any or all of the array members may be represented by a variable.

Variables in command addresses: The value of a variable can be assigned to one or all of the "address" elements of command. For example:

First, initialize the variable in a macro:

@foo@=2

and then somewhere else in the same macro, or in another macro...

outgn(@foo@)=0

In this case the value of variable @foo@ determines which output channel is assigned a gain of 0. This is a powerful device control technique. Here's another example:

outgn(@foo@[2])=0

More on variable initialization: To prevent trouble with "uninitialized" variables shared between multiple macros, it is often a good idea to initialize them all at once in a macro that is guaranteed to run before any other macro. This is one of the purposes of the Run on Powerup macro, which provides a handy place for one-time variable initializations. It will be run exactly once, at powerup. For preset specific intializations, a Preset Run on Recall macro can be designated for each preset in the DM84. This macro will be run every time the preset is recalled.

Number of variables: The maximum number of variables that may be initialized in the DM84 is 32 .

 

Loops

A loop is the familiar "while-do" statement used to execute one or more instructions - based on the current value of a comparison, a logical expression, or a combination of both. This expression is the "condition" and MUST be enclosed in parentheses. The value of the condition is a boolean type, and whether or not the loop continues or terminates depends on whether the condition is "true" or "false". The "actions" are one or more DM84 simple commands or update commands, enclosed in '`' (backtick) characters. Multiple instructions MUST be separated by a ';' (semicolon) character. The special keywords "while" and "do" MUST be lowercase. For example:

And so on. The maximum length of a DM84 command(s) supplied as the "action" is 63 characters. Commands given as an "action" of the loop MUST be enclosed within backtick characters - this is the character usually found on the same key as the tilde ('~'), in the upper left corner of your keyboard.

The use of loops allows device properties and variables that are arrays of values to be conveniently and efficiently accessed - a single loop instruction can replace many individual instructions.

 

Conditionals

A conditional is the familiar "if-then-else" statement used to control what happens - based on the current value of a comparison, a logical expression, or a combination of both. This expression is the "condition" and MUST be enclosed in parentheses. The value of the condition is a boolean type, and the action (if any) to be taken depends on whether the condition is "true" or "false". The "actions" are one or more DM84 simple commands or update commands, enclosed in '`' (backtick) characters. Multiple instructions MUST be separated by a ';' (semicolon) character. The special keywords "if", "then" and "else" MUST be lowercase. For example:

And so on. The maximum length of a DM84 command(s) supplied as an "action" is 63 characters. Commands given as an "action" of the conditional MUST be enclosed within backtick characters - this is the character usually found on the same key as the tilde ('~'), in the upper left corner of your keyboard.

The use of conditional logic gives the macro language its power. Variables shared between macros can drive behavior that is adapted to current circumstances - which preset is active, the state of some programmable input, or the current value of a device setting like output gain or mute status.

 

Loops and Conditionals combined

Loops and conditionals may be combined (nested) in certain ways:

Important: note that in both cases the "action" part of the "inner" instruction is treated specially - the backtick characters ('`') which enclose it need to be "escaped" with a backslash character ('\') since they are nested within another pair of backticks. This also applies to variable assignments made by invoking a built-in command - do this:

if(@foo@)then`@bar@=\`ingn(*)\`` 

NOT this:

if(@foo@)then`@bar@=`ingn(*)``.

Otherwise the macro processor will get confused about which backtick character goes with which.

No other combination is possible - loops may not be contained within another loop instruction, nor may a conditional be contained within another conditional instruction.

 

Copyright 2006 Lectrosonics, Inc.