next up previous
Next: Low Level MIDI Commands Up: Reference Manaul Previous: Repeats

Subsections


Variables, Conditionals and Jumps

To make the processing of your music easier, MMA supports a very primitive set for variable manipulations along with some conditional testing and the oft-frowned-upon goto command.

Variables

MMA lets you set a variable, much like in other programming languages and to do some basic manipulations on them. Variables are most likely to be used for two reasons:

To begin, the following list shows the available commands to set and manipulate variables:

Set VariableName String
Mset VariableName ... MsetEnd
UnSet VariableName
ShowVars
Inc Variablename [value]
Dec Variablename [value]
Vexpand ON/Off

All variable names are case-insensitive. Any characters can be used in a variable name. The only exceptions are that a variable name cannot start with a ``$'' or a ``_'' (an underscore--this is reserved for internal variables, see below).

Variables are set and manipulated by using their names. Variables are expanded when their name is prefaced by a space followed by single ``$'' sign. For example:

Set Silly Am / Bm /
1 $Silly

The first line creates the variable ``Silly''; the second creates a bar of music with the chords ``Am / Bm /''.

Note that the ``$'' must be the first item on a line or follow a space character. For example, the following will NOT work:

Set Silly 4a;b;c;d;
1 Am {$Silly}

However:

1 Am { $Silly}

will work fine.

Following are details on all the available variable commands:

Set [string]

Set or create a variable. You can skip the String if you do want to assign an empty string to the variable. A valid example is:

Set PassCount 1

Mset [lines] MsetEnd/EndMset

This command is quite similar to Set, but Mset expects multiple lines. An example:

MSet LongVar
1 Cm
2 Gm
3 G7
MsetEnd

It is quite possible to set a variable to hold an entire section of music (perhaps a chorus) and insert this via macro expansion at various places in your file.

Each Mset must be terminated by a EndMset or MsetEnd command (on its own separate line).

UnSet VariableName

Removes the variable. This can be useful if you have conditional tests which simply rely on a certain variable being ``defined''.

ShowVars

Displays the names of the defined variables and their contents. Mainly used for debugging. The display will preface each variable name with a ``$''. Note that internal MMA variable are also displayed with this command.

Inc and Dec

These commands increment or decrement a variable. If no argument is given, a value of 1 is used; otherwise, the value specified is used. The value can be an integer or a floating point number.

A short example:

Set PassCount 1
Set Foobar 4
Showvars
Inc FooBar 4
Inc PassCount
ShowVars

This command is quite useful for creating conditional tests for proper handling of codas or groove changes in repeats.

VExpand On or Off

Normally variable expansion is enabled. These two options will turn expansion on or off. Why would you want to do this? Well, here's a simple example:

Set LeftC Am Em
Set RightC G /
VExpand Off
Set Full $LeftC $RightC
VExpand On

In this case the actual contents of the variable ``Full'' is ``$LeftC $RightC''. If the Off/On option lines had not been used, the contents would be ``Am Em G /''. You can easily verify this with the ShowVars option.

When MMA processes a file it expands variables in a recursive manner. This means that, in the above example, the line:

1 $Full

will be changed to:

1 Am Em G /

However, if later in the file, you change the definition of one of the variables ...for example:

Set LeftC Am /

the same line will now be ``1 Am / G /''.

Most of MMA's internal commands can be redefined with variables. However, we really don't think you should use this feature. It's been left for two reasons: it might be useful, and, it's hard to disable.

However, not all commands can be redefined. The following is short list of things which will work (but, again, we're not suggesting you do this):

Set Rate Tempo 120
$Rate
Set R Repeat
$R

But, the following will not work:

Set B Begin
Set E End
$B Arpeggio Define
....
$E

This fails since the Begin/End constructs are expanded before variable expansion. However:

Set A Define Arpeggio
Begin $a ... End

is quite alright.

Even though you can use a variable to substitute for the Repeat or If directives, using one for RepeatEnd/EndRepeat, RepeatEnding. Label or IfEnd/EndIf will fail.

Variable expansion should usually not be a concern. In most normal files, MMA will expand variables as they are encountered. However, when reading the data in a Repeat, If or Mset section the expansion function is skipped--but, when the lines are processed, after being stored in an internal queue, variables are expanded.

Predefined Variables

For your convenience MMA tracks a number of internal settings and saves their values in variables you can access just like you would a user defined variable. All of these ``internal'' variables are prefaced with a single underscore. For example, the current tempo is saved in the variable _TEMPO; this can be accessed in your script with the notation $_TEMPO.

_Groove
Name of the currently selected groove. May be empty if no groove has been selected.

_LastGroove
Name of the groove selected before the currently selected groove.

_SeqSize
Current SeqSize setting.

_Tempo
Current Tempo. Note that if you have used the optional bar count in setting the tempo this will be the target tempo.

_Time
The current Time (beats per bar) setting.

_Transpose
Current Transpose setting.

_Volume
Current global volume setting.

_LastVolume
Previously set global volume setting.

_Debug
Current debug settings.

_LastDebug
Debug settings prior to last Debug command. This setting can be used to restore settings, ie:

Debug Warnings=off
... stuff generating annoying warnings
Debug $_LastDebug

Conditionals

The most important reason we created variables in MMA was to use them in conditionals. In MMA a conditional consists of a line starting with an If directive, a test, a series of lines to process (depending upon the result of the test), and a closing EndIf or IfEnd14.1 directive. An optional Else statement may be included.

The first set of tests are unary (they take no arguments):

Def VariableName
Returns true if the variable has been defined.

Ndef VariableName
Returns true if the variable has not been defined.

In the above tests you must supply the name of a variable--don't make the mistake of including a ``$'' which will invoke expansion and result in something you were not expecting.

A simple example:

If Def InCoda
  5 Cm
  6 /
Endif

The other tests are binary (they take two arguments):

LT Str1 Str2
Returns true if Str1 is less than Str2. (Please see the discussion below on how the tests are done.)

LE Str1 Str2
Returns true if str1 is less than or equal to Str2.

EQ Str1 Str2
Returns true if str1 is equal to Str2.

NE Str1 Str2
Returns true if str1 is not equal to Str2.

GT Str1 Str2
Returns true if str1 is greater than Str2.

GE Str1 Str2
Returns true if str1 is greater than or equal to Str2.

In the above tests you have several choices in specifying Str1 and Str2. At some point, when MMA does the actual comparison, two strings or numeric values are expected. So, you really could do:

If EQ abc ABC

and get a ``true'' result. The reason that ``abc'' equals ``ABC'' is that all the comparisons in MMA are case-insensitive.

You can also compare a variable to a string:

If GT $foo abc

will evaluate to ``true'' if the contents of the variable ``foo'' evaluates to something ``greater than'' ``abc''. But, there is a bit of a ``gotcha' here. If you have set ``foo'' to a two word string, then MMA will choke on the command. In the following example:

Set Foo A B
If GT $Foo abc

the comparison is passed the line:

If GT A B abc

and MMA seeing three arguments generates an error. If you want the comparison done on a variable which might be more than one word, use the ``$$'' syntax. This delays the expansion of the variable until the If directive is entered. So:

If $$foo abc

would generate a comparison between ``A B'' and ``ABC''.

Delayed expansion can be applied to either variable. It only works in an If directive.

Strings and numeric values can be confusing in comparisons. For example, if you have the strings ``22'' and ''3'' and compare them as strings, ``3'' is greater than ``22''; however, if you compare them as values then 3 is less than 22.

The rule in MMA is quite simple: If either string in a comparison is a numeric value, both strings are converted to values. Otherwise they are compared as strings. 14.2

This lets you do consistent comparisons in situations like:

Set Count 1
If LE $$Count 4
  ....
IfEnd

Note that in the above example we could have used ``$Count'', but you should probably always use the ``$$'' in tests.

Much like other programming languages, an optional Else condition may be used:

If Def Coda
  Groove Rhumba1
Else
  Groove Rhumba
Endif

The Else statement(s) are processed only if the test for the If test is false.

Nesting of Ifs is permitted:

If ndef Foo
  Print Foo has been defined.
Else
  If def bar
    Print bar has been defined. Cool.
  Else
    Print no bar...go thristy.
  Endif
Endif

works just fine. We've used indentation in our examples to clearly show the nesting and conditions. We suggest you do the same.

Goto

The Goto command redirects the execution order of you script to the point at which a Label has been defined. There are really two parts to this:

  1. A command defining a label, and,
  2. The Goto command.

A label is set with the Label directive:

Label Point1

The string defining the label can be any sequence of characters. Labels are case-insensitive. You can not set two points in your file to the same label.

To cause execution to jump to a labeled point:

Goto Point1

This causes an immediate jump. Any remaining lines in a repeat or conditional segment are discarded.

MMA does not check to see if you are jumping into a repeat or conditional section of code--but doing so will usually cause an error. Jumping out of these sections is usually safe.

For an example of how to use some simple labels to simulate a ``DS al Coda'' examine the file ``lullaby-of-Broadway'' in the sample songs directory.


Footnotes

...IfEnd14.1
We probably suffer from mild dyslexia and can't remember if the command is IFEND or ENDIF, so both are permitted. Use whichever is more comfortable for you.
... strings.14.2
An attempt is made to convert each string to a float. If conversion of both strings is successful, the comparison is made between two floats, otherwise two strings are used.

next up previous
Next: Low Level MIDI Commands Up: Reference Manaul Previous: Repeats
2004-09-21