Subsections

- DefCall
- Call

#
Subroutines

MMA supports primitive subroutines as part of its language. The format and usage is deliberately simple and limited ...we're really not trying to make MMA into a functional programming language.22.1

#
DefCall

Before you can use a subroutine you need to create it. Pretty simple to do. First, here is a subroutine which does not have any parameters:

defCall MyCopyright print Adding copyright to song MidiCopyright (C) Bob van der Poel 2014 endDefCall

Note that the subroutine definition starts with DEFCALL and is terminated by ENDDEFCALL or DEFCALLEND. The name of the subroutine and any parameters must be on the same line as DEFCALL and ENDDEFCALL must be on a line by itself. The body of the subroutine can contain any valid MMA command or chord data (including other DEFCALL and CALL commands).

Subroutines must be defined before they can be used. This can be done in the main song file, or in a different file you have included (including library files).

So, now you can insert a copyright message into your midi file just by calling the subroutine:

Call MyCopyright

Of course, you'll be using the same message every time ... so, let's make it a bit more useful be including a parameter:

defCall Copyright Name print Adding copyright to song: $Name MidiCopyright $Name endDefCall

Note that we have a parameter to the subroutine with the name ``Name''. In the body of the subroutine we reference this using the name $Name. In this case, to assign copyright to ``Treble Music'' we'd use:

Copyright (c) 2020 Treble Music

If you need to pass more than one parameter, separate each one using a single comma. Let's assume that you find that you have a large number of 2 measure chord repetitions in your song and you are tired of typing:

Am / Gm Edim / Gm Am / Gm Edim / Gm ...

You could define a subroutine for this:

DefCall 2Bars C1 , C2 , Count Repeat $C1 $C2 RepeatEnd $Count

And call it with:

Call 2bars Am / Gm , Edim / Gm , 7

to generate a total of 14 bars of music.22.2 If you doubt that this is working, call MMA with the -r option (see here).

Some points to remember:

- MMA subroutines do not have local variables. Everything is global.

- MMA subroutines do not return values to the caller. However, it is possible to use the built-in STACKVALUE macros (see here).

- You can use macros in a subroutine. Macros will not be expanded until the subroutine is executed.

- Both the subroutine name and the parameters are case insensitive.

- When a subroutine is executed parameters are expanded. Assuming that you have used the parameter ``P1'' in the definition of the subroutine and passed the value ``Am'' when calling, MMA changes any occurrences of ``$P1'' in the body of the subroutine to ``Am''. One limitation of this scheme is that if you have a macro of the same name it will be changed to the contents of the parameter before the line is parsed for execution: your macro will be ignored.

# Call

As discussed above, you execute a defined SUBROUTINE via the CALL command. There are three parts to this command:

1. The keyword CALL,
2. The subroutine name,
3. A list of parameters to be passed. If there is more than one parameter you must use commas to separate them.

If you wish to have a literal comma in a parameter you must escape it by prefacing it with a single backslash. So,

Call Prt My, what a nice song

will pass two parameters (``My'' and ``what a nice song'') to the subroutine ``Prt''.

On the other hand:

Call Prt My what a nice song

passes only one parameter (``My, what a nice song'').

Notes:

- There is no check to check for excessive nesting or recursion. You're on your own.

#### Footnotes

... language.22.1
  If you do solve the Towers of Hanoi using MMA subroutines, please let us know.
... music.22.2
  In this case we are using the MMA primitive REPEAT/ENDREPEAT, but it could also be accomplished with a counter, LABEL and GOTO ... we'll leave that as an exercise for the reader.