Macros

Simple Macros (without parameters)

Macros can be defined to avoid retyping or to give mnemonic names to
things. A macro is defined with the following syntax:

define macro_name macro_text@

The macro_name consists of one or more upper case letters, digits,
and underscores, with the first character being a letter.
The macro_text can be any text. It can be any length from empty
to many pages. The "@" terminates the macro. A literal "@" can be
placed in the macro_text by preceding it with a backslash.
If you want a literal backslash in the macro_text, it also must
be preceded by a backslash.

A macro is called by stating the macro_name in the input. The
macro_name is replaced by the macro_text.
A macro can be defined at any point in the input. It can be used as
often as desired any time after it has been defined. A given macro_name
can be redefined as many times as desired, with each new definition
overwriting the previous definition.

As an example, suppose you are printing an orchestral score, and the oboe
part happens to be on staff 5. Rather than having to remember which staff
it is, you could define a macro:

define OBOE 5: @

Not only is the name easier to remember than a number, but if you later
decide to move the oboe part to a different place in the score, only the
macro definition and perhaps a few other things would have to be changed.

Another common use of macros might be if a musical motif occurs several
times. You could define a macro for the motive:

define SCALE 8c;d;e;f;g;a;b;c+; @

then do something like:

OBOE SCALE

It is possible to remove the definition of a macro using the "undef"
statement:

undef OBOE

It is possible to have parts of the input skipped over depending on whether
certain macros are defined or not. This is done using
"ifdef," "else," and "endif." The keyword "ifdef" is followed by
a macro name. If a macro by that name is currently defined,
Mup will continue
reading and processing input normally. If it finds a matching "else,"
it will skip over input until the matching "endif."
If the macro is not currently defined, Mup will skip over the input
until it finds a matching "else" or "endif." There is also
an "ifndef" command that uses the opposite logic: it will read the input
up to the "else" or "endif" only if the macro is NOT defined.

The ifdefs can be sprinkled between other items in the input;
they need not be on separate lines. They can be nested. Examples:

Macro text cannot begin or end in the middle of a token, like a keyword or
a number or a string. Usually it will be clear what things are tokens;
generally tokens end where you are allowed to have white space.
But there are a few obscure cases. For historical reasons that are now hard to
change, "dashed tie" or "dashed slur" or the
per-note versions of "dashed ~" and " dashed <>" (or the "dotted" counterparts
of any of these) are treated as a single token. That means
you can't define one macro for "dashed" and another for "tie"
and put them together and have that be recognized.

Macros with parameters

Macros defined within Mup input can be defined to have "parameters."
This may be useful
when you have something that is repeated with small variations.
When defining a macro with parameters, the macro name must be followed
immediately by a ( with no space between the end of the name and the
parenthesis. The opening parenthesis is followed by one or more
parameter names, separated by commas, and ending with a close parenthesis.
Parameter names have the same rules as macro names: they consist of
upper case letters, numbers, and underscores, starting with an upper case
letter. The parameter names can then appear in the text of the macro
definition where you want a value to be substituted.

As an example, suppose you are doing a score with staffs 1 through 4
for vocal parts, and staffs 5 and 6 for a piano accompaniment, and that
you frequently want to mark a dymanics change at the same point in time
below each of the vocal scores and between the two piano staffs.
You could typically do this with something like:

boldital below 1-4: 1 "ff";
boldital between 5&6: 1 "ff";

but if you needed to do this lots of times, it could get tedious.
So let's define a macro with parameters:

This macro has two parameters,
which have been given the names COUNT and VOLUME.
When you call the macro, you will give them values.
For example,

DYN(1,"ff")

would give a VOLUME of "ff" at COUNT 1, whereas

DYN(3.5,"mp")

would give a VOLUME of "mp" at COUNT 3.5.

When calling a macro with parameters, the values to give the parameters
are given inside parentheses. The values are separated by commas.
The values in the parentheses are copied exactly as they are,
including any spaces, newlines, macro names, etc.
There are only a few exceptions to this:
you can include a comma, closing parenthesis, or backslash
as part of a parameter value by preceding it with a backslash, and
a backslash followed by a newline
in a parameter value will be discarded. Thus a macro call of

MAC(\\\,\))

has one parameter, the text of which is 3 characters long: a backslash,
comma, and closing parenthesis.
If you backslash other characters they will be copied without the backslash,
but doing this on anything other than a double quote will produce a warning,
because it seems unlikely the backslash was really needed.

Conceptually, when the macro is expanded, the backticks are replaced
by double quote marks, but in addition,
any double quote mark found in the value being passed to the parameter will
have a backslash inserted before it, and any backslash that occurs
within double quotes in the value will also have a backslash inserted
before it. Thus, for example:

Sometimes it can be a little tricky to get the number of backslashes right,
or other details like that.
The -E Mup command line option
shows how macros will expand, which may help you figure out what to do.

Saving and restoring macros

You can take a snapshot of all your current macro definitions by using
the savemacros command, and then restore that set of definitions later
using the restoremacros command. These are both followed by a quoted
string, which is a name you give to the saved definitions.
This might be useful if, for example, you had a multi-movement piece,
and wanted to use one set of macros on the first and third movements,
but a completely different set on the second movement. You could save
the macro state at the very beginning under one name,
and after the first movement under a different name. Before the second
movement, you could restore to the original state with no macros defined,
and define your second set. Before the third movement, you could restore
the macros as they had been at the end of the first movement.

Another possible use would be if you have several standalone files,
each containing a complete song, and you want to "include" those files
in a another file. By putting a save/restore around each
include,
you can prevent any macro definitions in one file from interacting with
those from another file.

Here is a very simple example, using single measures rather than a whole
movement or song.

// Define one "global" macro that will stay around,
// by defining it before doing any savemacros.
define ONE_MEAS
score
BSTYLE
music
1: 8c;;e;;A 2g;
bar
@
// Save just that one macro as the "default."
savemacros "default"
// Now define a couple other macros and save the macros.
define BSTYLE beamstyle=2,2 @
define A [with >] @
// Note that the name can be any arbitrary text string.
savemacros "2,2 >"
// Restore the default setting and set macros
// with the same names to different values.
restoremacros "default"
define BSTYLE beamstyle=4,4,4,4 @
define A [with ^] @
savemacros "4,4,4,4 ^"
// Now use the "global" macro with each saved macro state.
restoremacros "2,2 >"
ONE_MEAS
restoremacros "4,4,4,4 ^"
ONE_MEAS

If you do another savemacros using the same name as you had already used,
the old state is forgotten and replaced with the new.

Often, though not always, you may want to use
saveparms/restoreparms
at the same places as you use savemacros/restoremacros.