Next: , Previous: `.fms' File Examples, Up: `.fms' File Examples


6.1 `.fms' File Features

The Tutorial section already gives an introduction to .fms files. The following examples summarize the syntax of `.fms' files and introduce extra features designed to make these files more flexible and easier to edit.

6.1.1 Comments

These are comments.

// this is a comment

time 0 dur 1 pitch 60; // comments can follow lines

/-
    this is a multiline comment
-/

time 1 dur 1 /- another comment -/ pitch 60;

ex007.png

Figure 6.1: Comments

6.1.2 General Syntax

The syntax for setting and parameter assignments is pretty flexible. You can use a ‘=’, ‘:’ or nothing at all between the setting/parameter id and its assigned value. To append to a list or replace entries in a mapping from strings to values, use a plus sign (i.e., use ‘+=’, ‘+:’ or ‘+’).

Strings can be surrounded by single or double quotes. If there are no characters that could be confused with the string's surrounding context (e.g., ‘,’, ‘)’, ‘=’, etc.) then quotes aren't necessary. A double quote inside a double-quoted string is specified with ‘\"’, a single quote inside a single-quoted string is specified with ‘\'’, and a space in an unquoted string is specified with ‘\ ’. Also, a tab character is specifed with ‘\t’ and a newline with ‘\n’.

Lists are enclosed in ‘(’ and ‘)’. Object definitions are enclosed in ‘<’ and ‘>’. Lists can optionally contain commas to separate elements. Setting/value pairs in object definitions can also be delimited by commas to assist readability. If a list is described in the documentation as a “mapping” from strings to values, then the string/value pairs can also be specified as assignments (i.e., using ‘=’ or ‘:’) and delimited by commas.

Floating point numbers always have a decimal point in them while integers, rationals and mixed numbers don't.

The example below demonstrates the variety of options described above.

title = "Syntax"
author: David\ Psenicka   // the `\' escape character makes this one string
quartertones yes
tuplets (7 3)
// appending to an existing list--note: `inst-defs' is more appropriately set in your `.fomus' initialization file
inst-defs += (<id = rec, name "Recorder", staves <clefs: <instclef: treble>>>)
note-symbols = ("a" = 9, // this setting is a mapping from strings (note symbols) to numbers (pitch classes)
                "b" = 11, // therefore you can make each string/number pair look like an assignment
                'c' = 0,
                d: 2
                e: 4
                f 5
                g 7
                A:9 B:11 C:0 D:2 E:4 F:5 G:7)

part <id="prt" inst:"rec">

voice (1, 2)
time 0.0 dur=1+1/3 pitch:60 ;
time 1.333
dur = 2/3  pitch : 66;

ex008.png

Figure 6.2: Syntax

6.1.3 Abbreviations

Many parameters and symbols have abbreviations, as shown below.

dyns = yes
part <id p1 inst "oboe">

// measures
time 0 dur 3 measure <>
time 0 dur 3 meas <>
time 0 dur 3 mea <>
time 0 dur 3 me <>
time 0 dur 3 e <>
time 0 dur 3 ||

// note event parameters
part p1 voice 1
note time 0 grace 0 duration 1/2 pitch 59 dynamic 1 ;
note time 0 duration 1 pitch 60 dynamic 1 ;
mark [.];

par p1 voi 1
not tim 2 gra 0 dur 1/2 pit 59 dyn 1 ;
not tim 2 dur 1 pit 60 dyn 1 ;
mar [.];

pa p1 vo 1
no ti 4 gr 0 du 1/2 pi 59 dy 1 ;
no ti 4 du 1 pi 60 dy 1;
ma [.];

a p1 v 1
n t 6 g 0 d 1/2 p 59 y 1 ;
n t 6 d 1 p 60 y 1;
m [.];

rest tim 7 dur 1 ;
res tim 8 dur 1 ;
re tim 9 dur 1 ;
r tim 10 dur 1 ;

ex046.png

Figure 6.3: Abbreviations

6.1.4 Note Events

Note events are created by specifying the values of parameters, settings and marks and “entering” the note with a ‘;’. One note event is created for each ‘;’ encountered in the file. To specify a rest or mark event, include the symbol rest or mark before the ‘;’ (the symbol note is also valid but unnecessary).

time 0 dur 1/2 pitch 60;
time + dur 1/2 pitch 62;
time + dur 1/2 pitch 64;
time + dur 1/2 pitch 65;
time + dur 1/2 pitch 67;
time + dur 1/2 rest [ferm];

time + dur 1/2 pitch 65 ;
time + dur 1/2 pitch 64 ;
time + dur 1/2 pitch 62 ;
time + dur 1/2 pitch 60 ;

mark time 3 dur 2 [.];

ex010.png

Figure 6.4: Note Events

6.1.5 Marks

Marks are specified by enclosing the mark symbol within a ‘[’ and ‘]’. If the mark requires an argument, it is also included within the brackets and separated from the mark symbol by a space or comma.

time 0 duration 1/2 pitch 56;
duration 1
time + pitch 55 [>];
time + pitch 56 [.];
time + pitch 57 [^];
time + pitch 56 [-];

duration 1/4
time 6 pitch 55 [(..];
time + pitch 56;
time + pitch 57;
time + pitch 56;
time + pitch 55 [(..];
time + pitch 56;
time + pitch 57;
time + pitch 56 [(..];
time + pitch 55;
time + pitch 56 [(..];
time + pitch 57 [(..];
time + pitch 56;
time + pitch 55;
time + pitch 56;
time + pitch 57 [..)];
time +
time + pitch 56 [x ":)"]; // (text) mark with argument
time + pitch 55 [x ":("];
time + pitch 56 [x, ":|"]; // (optional comma)

ex011.png

Figure 6.5: Marks

6.1.6 “Sticky” Values

When the values of the following parameters are set, they “stick” until the next time they are set in the file: time, duration, pitch, part, voice, dynamic and grace. When FOMUS encounters a ‘;’, a note event is constructed from these arguments in whatever current states they are in. This allows you to represent constructs such as chords and melodies more efficiently and in a style that's easier to read than when all parameters are specified for each individual note.

duration 1/2
time 0     pitch 55; // melody
time 1/2   pitch 56;
time 1     pitch 57;
time 1+1/2 pitch 58;
time 2     pitch 59;
time 2+1/2 pitch 60;

duration 1
time 3     pitch 55; // chords
           pitch 60;
           pitch 66;
time 4     pitch 56;
           pitch 61;
           pitch 67;
time 5     pitch 56;
           pitch 61;
           pitch 67;

voice 1
time 6      dur 1/4 pitch 72; // separate voices
time 6+1/4  dur 1/4 pitch 73;
time 6+1/2  dur 1/2 pitch 74;
time 7      dur 1   pitch 75;
time 8      dur 2   pitch 76;
time 10     dur 4   pitch 77;

voice 2
time 6      dur 4   pitch 60;
time 10     dur 2   pitch 59;
time 12     dur 1   pitch 58;
time 13     dur 1/2 pitch 57;
time 13+1/2 dur 1/4 pitch 56;
time 13+3/4 dur 1/4 pitch 55;

ex003.png

Figure 6.6: Sticky Values

grace behaves in a special manner. Whenever time is set to some value, grace is “reset” (i.e., the next note isn't a grace note until another grace value is encountered). As long as time isn't given a value, grace behaves in a sticky manner like all of the other arguments.

time 1/2 dur 1/4
  grace 0   pitch 59;
  grace 1/4 pitch 62;
  grace 1/2 pitch 54;
            pitch 65;

time 1/2 dur 1/2 pitch 40;
time +   dur 1/2 pitch 49;

time 1+1/2 dur 1/4
  grace 0   pitch 70;
  grace 1/4 pitch 76;
  grace 2/4 pitch 73;
  grace 3/4 pitch 74;

ex004.png

Figure 6.7: Sticky Grace Values

Marks don't behave stickily. The entire set of marks must be specified for each individual note. Setting assignments are also not sticky—like marks, they must appear in each individual note. If you need to specify marks and settings for large groups of notes, define a region (see below for an example).

6.1.7 Time Increments

A ‘+’ following the time parameter is an instruction to increment the time by the last duration value. ‘+’ can also be used to increment “grace time” in the same way.

duration 1
time 0 pitch 60;

duration 1/2
time + pitch 61;
time + pitch 60;
time + pitch 59;
time + pitch 60;

duration 1/3
time + pitch 61;
time + pitch 62;
time + pitch 61;
time + pitch 60;
time + pitch 59;
time + pitch 58;
time + pitch 59;
time + pitch 60;
time +

time 6 duration 1/4
  grace 0 pitch 70;
  grace + pitch 66;
  grace + pitch 62;
time 6 duration 1 pitch 63;

ex001.png

Figure 6.8: Time Increments

6.1.8 Extending Time/Duration

A ‘+’ following the duration parameter is an instruction to set the duration of the note so that it ends where the next note begins in the same voice. A ‘-’ following a duration parameter is an instruction to end the note at the given time, and place the onset at the end time of the previous note in the same voice.

time 0 duration + pitch 60;
time 1 duration + pitch 66;
time 1+1/2 duration + pitch 59;
time 3 duration + pitch 62;
time 3+1/2 duration + pitch 64;
time 5 duration + pitch 61;
time 6 duration 1/2 pitch 69;

time 8 duration 1/2 pitch 60;
time 9 duration - pitch 66;
time 9+1/2 duration - pitch 59;
time 11 duration - pitch 62;
time 11+1/2 duration - pitch 64;
time 13 duration - pitch 61;
time 14 duration - pitch 69;

ex002.png

Figure 6.9: Time Extensions

6.1.9 Regions

{’ and ‘}’ are used to surround a group of entries and modify them in some way. A region beginning with ‘time +4 {’, for example, increments all of the time values in the region by 4. For time, grace duration and dyn, any one of ‘+’, ‘-’, ‘*’ and ‘/’ can be used (i.e., times, durations and dynamics can be scaled using ‘*’ and ‘/’ as well as incremented using ‘+’ and ‘-’). It's important to note that if you scale time with a region specification like ‘time *2 {’ or ‘time /2 {’, this only scales time values, not duration values. For example, ‘time *2 {’ should usually be accompanied by ‘dur *2 {’ to produce the effect you probably want. pitch may be modified with ‘+’ or ‘-’ but not scaled like time and dur.

voice can be altered by specifying a voice or list of voices to add or subtract from all of the enclosed note events. For example, voice +2 { means voice 2 is an additional choice for all enclosed note events (2 is added to each event's list of voices) while ‘voice -2 {’ means voice 2 is never a choice regardless of what is specified in each note event (2 is removed from each event's list of voices). ‘voice 2 {’ means simply set all enclosed events to voice 2. Mark regions can also be defined, and behave in a manner similar to voice regions. For example, ‘[.] {’ or ‘+[.] {’ means a staccato mark is added to all enclosed note events while ‘-[.] {’ means staccato marks are removed from all enclosed note events regardless of whether or not they are specified in individual notes.

time 0 duration 1
pitch 60; pitch 67; pitch 72;

time +1 {
time 0 duration 1
pitch 60; pitch 67; pitch 72;
}

pitch +7 { // transpose up a fifth
time 3 duration 1
pitch 60; pitch 67; pitch 72;
}

time +4 { // everything inside is offset by +4
time /2 { // scale time and duration by 1/2
dur /2 {

time 0 duration 1 // the actual time is (0 / 2) + 4 = 4
pitch 60; pitch 67; pitch 72;

time 1 duration 1 // the actual time is (1 / 2) + 4 = 4+1/2
pitch 60; pitch 67; pitch 72;

time 2 duration 1
pitch 60; pitch 67; pitch 72;

} } }

voice (1 2)
time 8 duration 1 pitch 67; pitch 73;
time + duration 1 pitch 69; pitch 75;
time + duration 1 pitch 71; pitch 77;

voice -2 { // remove voice 2
time + duration 1 pitch 67; pitch 73;
time + duration 1 pitch 69; pitch 75;
time + duration 1 pitch 71; pitch 77;
}

voice -(1) { // remove voice 1
time + duration 1 pitch 67; pitch 73;
time + duration 1 pitch 69; pitch 75;
time + duration 1 pitch 71; pitch 77;
}

voice 1
time + duration 1 pitch 67; pitch 73;
time + duration 1 pitch 69; pitch 75;
time + duration 1 pitch 71; pitch 77;

voice 2 { // set voices to 2
time + duration 1 pitch 67; pitch 73;
time + duration 1 pitch 69; pitch 75;
time + duration 1 pitch 71; pitch 77;
}

time 24 duration 1/2
pitch 60;
time + pitch 61;
time + pitch 62;
+[.] { // `+' is optional and doesn't make any difference in this case
time + pitch 63;
time + pitch 64;
time + pitch 65;
[>][x "$"] { // both marks are added
time + pitch 66;
time + pitch 67;
time + pitch 68;
-[>] { // remove the accent
time + pitch 69;
time + pitch 70;
time + pitch 71;
} } }

ex005.png

Figure 6.10: Regions

Some of the regions in the example above are nested. When numerical values like time or pitch are being modified, the effects accumulate. When lists of things (like voices or marks) are being modified inner regions take precendence over the outer ones. Regions can also overlap. To specify which ‘{’ belongs to which ‘}’ you must attach matching tag strings to them (e.g., ‘a{’ would match ‘}a’ and ‘foo{’ would match ‘}foo’). Also, a region extending to the end of the file can be defined with an alternate syntax using ‘..’ or ‘...’ instead of ‘{’ (e.g., ‘time +1 ...’).

time 0 duration 1/2
pitch 60;
time + pitch 61;
time + pitch 62;
[.] {
time + pitch 63;
time + pitch 64;
time + pitch 65;
[>] {
time + pitch 66;
time + pitch 67;
time + pitch 68;
}
time + pitch 69;
time + pitch 70;
time + pitch 71;
}

time +8 ...  // the space is necessary so that fomus sees `8' and not `8.'

time 0 duration 1/2
pitch 60;
time + pitch 61;
time + pitch 62;
[.] s{
time + pitch 63;
time + pitch 64;
time + pitch 65;
[>] a{
time + pitch 66;
time + pitch 67;
time + pitch 68;
}s
time + pitch 69;
time + pitch 70;
time + pitch 71;
}a

ex006.png

Figure 6.11: Nested and Overlapping Regions

Settings can also be specified for groups of notes using regions. In the following example staff is set to 1 for the first four note entries and 2 for the next four. The ‘time 0’ is necessary to tell FOMUS that the following ‘staff = 1’ is not a score-level setting (which must appear before anything else in the file) but a note event setting (see Settings (File)).

// this extra `time 0' is here to tell FOMUS we're done with score-level
// settings and entering note events now
time 0

staff = 1 {
time 0 dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
}
staff = 2 clef = treble { // two settings in this region
time + dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
time + dur 1 pitch 60 ;
}

ex016.png

Figure 6.12: Settings in Regions

6.1.10 Note/Rhythm Symbols

Notes and durations can be specified symbolically using strings in .fms files. A pitch symbol begins with a note letter followed optionally by one or two accidentals (the second accidental is a microtone adjustment) and an octave number (middle C is ‘c4’). If the octave number is omitted, the pitch closest to the last specified pitch is used. It is important to note that by specifying pitches this way you are not specifying notation (i.e., ‘cs4’ could turn out to be a C-sharp, D-flat or B-doublesharp in the score regardless of the ‘s’ in the symbol), they are only a convenient way of representing numeric values. To actually force FOMUS to use a sharp, you would have to use the acc setting.

Duration symbols consist of a base string (e.g., ‘q’ signifies a quarter note, ‘e’ signifies an eighth note, etc.), a dot or double-dot symbol, and an optional tuplet modifier (e.g., ‘t’ multiplies the value by 2/3, ‘q’ multiplies the value by 4/5, etc.). The symbol may also be followed by a tie (the ‘+’, ‘_’ or ‘~’ characters can be used) and another duration symbol, in which case the two duration values are added together. Like pitch symbols, rhythmic symbols map strictly to FOMUS time values and don't necessarily signify the rhythmic spelling of the note. For example, the default symbol ‘s’ specifies a sixteenth note only when the beat setting is set to 1/4 (1 beat equals 1 quarter note—see setBeat). If you change the value of beat to 1/8, ‘s’ outputs a 32nd note instead since it still represents 1/4 of a beat. (The reason for this discrepancy is that, under some conditions, it would be impossible for FOMUS to determine proper event times and durations if logical values are mixed with notation symbols.)

quartertones = yes

time 0 duration s pitch c3; // octave is given only on first note
time + duration e pitch dn; // d natural
time + duration q pitch ef;
time + duration h pitch fs;
time + duration w pitch gb;
time + duration e. pitch f#; // dot modifiers
time + duration q. pitch e-;
time + duration h. pitch d+;
// tuplet modifiers
time 20 duration qt pitch cns4; // one quartertone sharp (natural-sharp)
time + duration qt pitch cnf;
time + duration qt pitch bff; // three quartertones flat (flat-flat)

time 24 duration q+s pitch css;

ex018.png

Figure 6.13: Pitch and Duration Symbols

The settings note-symbols, note-accs, note-microtones and note-octaves contain all of the information for parsing notes while dur-symbols, dur-dots, dur-tie and tuplet-symbols contain information for parsing durations. Look up the values of these settings to see all of the options available for constructing symbols, or customize them if the default values are insufficient. The following example shows how to do this:

// these settings are all "mappings" from strings to numbers
note-symbols = (do = 0, re = 2, mi = 4, fa = 5, sol = 7, la = 9, ti = 11)
note-accs = (flat = -1, sharp = 1, natural = 0)
note-microtones = (flat = -1/2, sharp = 1/2, natural = 0)
note-octaves = (",,," = 12, ",," = 24, "," = 36, "." = 48, "'" = 60,
        	"''" = 72, "'''" = 84, "''''" = 96, "'''''" = 108)

dur-symbols = (whole = 4, half = 2, quarter = 1, eighth = 1/2, sixteenth = 1/4)
dur-dots = (dotted = 1+1/2, doubledotted = 1+3/4)
dur-tie = ("-")
tuplet-symbols = (quint = 4/5, triplet = 2/3)

quartertones = yes

time 0 duration sixteenth pitch do.;
time + duration eighth pitch renatural;
time + duration quarter pitch miflat;
time + duration half pitch fasharp;
time + duration whole pitch solflat;
time + duration eighthdotted pitch fasharp; // dot modifiers
time + duration quarterdotted pitch miflat;
time + duration halfdotted pitch resharp;
// tuplet modifiers
time 20 duration quartertriplet pitch donaturalsharp'; // one quartertone sharp (natural-sharp)
time + duration quartertriplet pitch donaturalflat;
time + duration quartertriplet pitch tiflatflat; // three quartertones flat (flat-flat)

time 24 duration quarter-sixteenth pitch dosharpsharp;

ex019.png

Figure 6.14: Custom Pitch and Duration Symbols

These settings also affect the appearance of symbols printed by the online documentation.

6.1.11 Including Other Files

To include another file, use the include instruction shown in the example below. Files may be included at any location, and can be in any format that FOMUS recognizes (e.g., a MIDI file).

// include the comments example at the beginning of this section
include "comments.fms"

time: 4 dur: 1+1/2 pitch: 30;

ex012.png

Figure 6.15: Including the Comments Example

6.1.12 Macros

Macros are text strings that can be inserted at any arbitrary location in the file. They are defined with the macro keyword followed by a string that specifies the name of the macro, a list of positional parameters, and finally a string that represents the macro body or replacement text. The ‘@’ character followed by the name of a parameter indicates that the appropriate argument is inserted at this location. Once the macro is defined, it may be invoked using the macro name followed by a list of arguments. The number of arguments must match the number of parameters in the macro definition.

// three versions of majchd are defined
macro majchd(ti du pi)
" time @ti
  dur @du pitch @pi ;
  pitch +4 { dur @du pitch @pi ; }
  pitch +7 { dur @du pitch @pi ; }"

macro majchd(du pi)
" time +
  dur @du pitch @pi ;
  pitch +4 { dur @du pitch @pi ; }
  pitch +7 { dur @du pitch @pi ; }"

macro majchd (pi) "majchd(2 @pi)" // invokes the macro above

macro noargs() "time 16 dur 4 pitch 60 ;"

majchd(0 1 60) // three arguments calls the first macro
majchd(+ 1 62)
majchd (1 64) // two arguments calls the second macro
majchd: (1 65) // alternate syntax
majchd: (2 67)
majchd = 72 // one argument selects the third macro (don't need the parentheses)

noargs()

// chord macro
macro chord (pit1 pit2) "pitch @pit1; pitch @pit2;"
macro chord (pit1 pit2 pit3) "pitch @pit1; pitch @pit2; pitch @pit3;"
macro chord (pit1 pit2 pit3 pit4) "pitch @pit1; pitch @pit2; pitch @pit3; pitch @pit4;"
macro chord (pit1 pit2 pit3 pit4 pit5) "pitch @pit1; pitch @pit2; pitch @pit3; pitch @pit4; pitch @pit5;"
// this macro shows how to handle string arguments
macro textmark (text) "[x \"@text\"]"

// redundant `;'s are ignored by fomus (i.e., it's okay for the chord macros to end with ';' and
// to be followed by an extra `;' here)
time = 20 dur = 2 chord = (60 62) ;
time = 22 dur = 2 chord = (64 66 68) ;
time = 24 dur = 2 pitch 72 textmark ";)" ;

ex017.png

Figure 6.16: Macros

All arguments are passed as strings. Since FOMUS executes macros by simply replacing text in the file, you can pass absolutely anything as an argument. Complex arguments with spaces, commas and other confusing characters can be passed by enclosing them in quotes. Also, you must be careful not give a macro the same name as a part, setting or event parameter to avoid potential conflicts.