Table of Contents
Table of Contents......................................................................................................................... 1
Introduction .................................................................................................................................. 2
Domain and Motivation .......................................................................................................................2
Language Properties.............................................................................................................................4
Syntax .........................................................................................................................................................4
Seeds....................................................................................................................................................................... 5
Sample Code.............................................................................................................................................6
Language Tutorial ....................................................................................................................... 9
Introduction.............................................................................................................................................9
Installing AMFM................................................................................................................................... 10
Hello World Program ........................................................................................................................ 10
Hello World Refined .......................................................................................................................... 13
Syntax Errors ........................................................................................................................................ 14
Beyond Hello World ........................................................................................................................... 15
Transformations ................................................................................................................................. 19
Multiple Transformations ............................................................................................................... 21
Continuous Play................................................................................................................................... 22
Reference Manual .................................................................................................................... 26
Introduction.......................................................................................................................................... 26
Composition Overview...................................................................................................................... 26
Implementation................................................................................................................................... 26
Lexical conventions............................................................................................................................ 27
Comments ......................................................................................................................................................... 27
Whitespace ....................................................................................................................................................... 27
Reserved Words ............................................................................................................................................. 27
End of Statement ............................................................................................................................................ 27
Tokens ................................................................................................................................................................ 28
Scope ....................................................................................................................................................... 29
Data Types ............................................................................................................................................. 29
Start Block ............................................................................................................................................. 30
Functions ............................................................................................................................................... 31
Grammar ................................................................................................................................................ 44
Team Mondegreen - AMFM project report 2
Introduction
Domain and Motivation
Music consists of sounds organized in time, and its structure (rhythm, harmony, melody,
structure, and texture) has been studied for several centuries. Music can be coded in
several ways, and many computer languages for its representation have been created in the
past few decades. Some languages are also intended to support composers and help them
explore new possible combinations of sounds. The expression Algorithmic Composition1
has recently emerged to describe the use of algorithms to create music. This can be
achieved using mathematical models, knowledge-based systems, grammars, evolutionary
methods, machine learning, or a combination of these approaches.
This tie between mathematics and music is one that has been explored, but this domain
certainly hasn‟t been fully analyzed. The idea of creating pleasant music from
mathematical algorithms in music is fascinating. The trouble becomes creating music
versus random noises. Bulmer (2000) describes this problem:
“White noise and brown noise can be seen as two extremes for random music. In white
noise there is no association between successive notes while for brown noise there is a
very strong association. White noise is dull because it is too unpredictable but brown noise
is also dull because it is too predictable. Interestingly, neither is predictable in the long
run.
Traditional music, on the other hand, seems to achieve a balance between these extremes.
A composer might sit down with a vision for a whole piece of music, devise finer structure
for smaller sections, and then write the notes for each section. This gives the pattern over
1
http://en.wikipedia.org/wiki/Algorithmic_music
Team Mondegreen - AMFM project report 3
time a long-range dependence while still involving short-term randomness.
This construction is reminiscent of the construction in the plane of the Koch snowflake, as
described in Mandelbrot (1982). The first four steps in making the snowflake are shown in
Figure 1. The result is an object, which is self-similar, possessing similar structures as you
look closer and closer at it. Such objects, whether they are in space, like the snowflake, or
in time, like musical notes, are called fractals.”
Figure 1. Creating a Koch snowflake
A large number of languages for music generation that we have encountered in our
search rely on the principle of self-similarity. In these languages some patterns are
extracted from a string of notes, and then used to evolve the same string of notes in a
fractal-like song. The most cited language of this kind is Fractal Composer2. Fractal
Composer allows the creation of interesting fractal-like songs with a very small
effort. A user is only required to define a “germ” (i.e. a small number of initial notes)
and some parameters, and a self-similar number of extensions are added, resulting in a
musical piece. This process produces interesting results, but somewhat limited by the fact
that only a germ can be specified, whereas music composition is often the result of
creative interleaving of different patterns and instruments that yield a pleasant
interaction.
AMFM makes use of self-similarity to assist the user with the composition, providing a
2
http://fractalcomposer.com/
Team Mondegreen - AMFM project report 4
mean of easily creating songs from an initial string of notes. Differently from Fractal
Composer, AMFM allows the definition of multiple patterns, providing a way of
interleaving them. As it suggests, AMFM is built upon a minimalistic concept hoping to
be a simple and easy to use language. It combines classically defined syntax and built in
functions to do this. The widespread use of the semicolon to end a statement is one
example of a classically defined syntax AMFM uses. Simple self explanatory names for
built in functions such as “play” and “start” also facilitate the minimalistic concept.
AMFM also relies on fractal composition, to allow a user to easily build songs by
providing some simple strings of notes. AMFM doesn‟t require more musical and
programming ability than what is required to users of Fractal Composer or a basic PERL
program. The language produces WAV files that can be edited and modified. The self
similar manipulations allows for an interesting musical experimentation.
Language Properties
AMFM is a functional language since it has no state and no mutable data. The output of
the compiler will be java code that uses the Java Sound API3 at its foundation. The java
program that is outputted will produce a WAV file.
Syntax
AMFM has a succinct syntax, which can be easily split into two parts. First there are seed
definitions. The second part is the start procedure that contains a list of functions called on the
3
http://java.sun.com/products/java‐media/sound/
Team Mondegreen - AMFM project report 5
defined seeds. A commented statement is preceded with // and each code statement ends with
a semicolon.
seed test1 The seed declaration
{ The open curly brace for the seed definition
PIANO; The instrument for this seed
A; A list of notes in this seed where more complex
C; note units can be used instead of just notes
} The end curly brace for the seed definition;
Notifies that the start procedure begins here
play(test1,1,1); Executes the play function on seed test1
} Ends the start procedure
// Comment (ends at the end of line)
A seed can only include one instrument declaration and one or multiple note units. More than
one seed can be defined. All seeds can be later used in the start procedure by the built in
functions.
Seeds
We borrow the syntax used by Fractal Composer for the specification of our seeds in
terms of the note units. The syntax for the note units has the following format:
“Pitch class” “octave”, “duration fraction”, “volume”
Pitch Class: A letter name (A to G), optionally followed by accidental (bb, b, # or
x)
Octave: A number from 0 to 9 specifying which octave this note is in.
Duration Fraction: A fraction or integer indicating how long the note should last.
Volume: One of PPP, PP, P, MP, MF, F, FF or FFF, listed in magnitude order.
Example of a seed:
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF;
A seed should only contain one instrument declaration otherwise a semantic error will be
thrown. A seed can obviously contain multiple note units.
Team Mondegreen - AMFM project report 6
Sample Code
Example I
seed test1{
PIANO;
A; G; C; D;
G; C; D#; C;
E5; C5; R; R;
}
seed test2 {
FLUTE;
C5,1/4; F5,1/8; E5,1/8; D5,1/8; F5,1/8; C5;1/4;
D,1/8; F,1/8; C,1/8; A,1/8; C5,1/4; A,1/4;
A,1/2; C,1/2;
}
start {
play(test1,1,3);
play(test2,1,3);
}
Team Mondegreen - AMFM project report 7
Example II
seed test1{
PIANO;
D,1/8; F,1/8; C,1/8; A,1/8; C5,1/4; A,1/4;
}
seed test2 {
FLUTE;
C5,1/4; F5,1/8; E5,1/8; D5,1/8; F5,1/8; C5;1/4;
}
start {
SSpitch_rhythm(test1,1,6,TRUE);
SSall(test2,1,6,TRUE);
}
The user starts by defining a few seeds. It can be one, two, or as many as needed. Seeds have two
parts. First, an instrument needs to be declared on the first line in all capitals followed by a
semicolon. The second part of a seed is the note units. Like seeds themselves, note units can
number as many as needed (provided there‟s more than one). Notice that we have kept the note
units on the same line so that each line is a measure of music. This is just a style that makes it
easy to read for the programmer.
Example I demonstrates how a classically train composer might use AMFM. The programmer
writes out exactly which notes will be played with no thought for the self-similarity
manipulations that AMFM offers. This type of programming, while not making the most of
AMFM, is certainly supported. Notice how the program‟s start procedure only contains a play
function hence; the program will output a wav file with no changes to the specifications from the
Team Mondegreen - AMFM project report 8
user.
Example II demonstrates the use of the self-similar functions. It is the hope of the AMFM writers
that programmers will play around with these functions and various seeds to produce fractal
music. The start function in this program makes use of the more advanced self-similar functions
(SS stands for self similar). The first one is the pitch and rhythm manipulations. The second runs
all three self-similar manipulations that AMFM supports (pitch, rhythm, and volume).
Team Mondegreen - AMFM project report 9
Language Tutorial
Introduction
Fractal music is a class of music that is self-similar. A fractal musical composition is built from
collections of musical notes, where the structure of the collections is similar to or derived from
the arrangement of the musical notes within the collection. AMFM is designed to facilitate
fractal music composition, though it is worth noting that it is possible to create music with
AMFM that, while fractal-like, does not fit the strict definition of fractal music. Often, AMFM is
used to create compositions with amalgamations of fractal-like music segments.
A musical fractal is a music segment that is composed of notes generated based on the
arrangement of an initial collection of seed notes. First, a pattern is extracted from the seed notes.
This pattern is then used to perform transformations on the seed notes, and thus generate new
collections of notes that are self-similar to the seed. AMFM supports three types of
transformations: pitch, rhythm and volume. Each transformation will analyze the implicit pitch,
rhythm or volume pattern in the seed and apply this pattern to the seed notes to generate a
musical fractal. AMFM as its name suggests has a minimal syntax, so the language user does not
have to be bogged down with many syntactic details and can focus on composing musical pieces
with very little code.
The following tutorial will introduce the AMFM fractal music language. The goal is to
familiarize the reader with the use of the language through a series of examples. This tutorial is
not a comprehensive guide to the structure or syntax of the language, but will introduce the
major concepts of AMFM, starting with the simplest case (a 'hello world' example), and
proceeding through more complex examples of generating fractal music.
Team Mondegreen - AMFM project report 10
Before diving into the language it is important to understand the mindset of fractal composition,
which can be very different from “traditional” ways to compose music. In fractal music we
define seeds and then apply self-similarity manipulations on them, which initially might make it
hard to imagine how the whole piece will sound, but part of the fractal composition is the
experimentation and discovering interesting pattern and sounds through a process of trial and
error.
One last caveat before we start, the tutorial assumes that the reader is familiar with music
notation, and music theory: scales, tones, rhythm, pitch etc.
Installing AMFM
Since AMFM generates Java program you must have Java installed on your machine (version
1.6) see the java page download page for more instructions for your specific operating system
installation (http://www.java.com/en/download/manual.jsp). Before you run AMFM on your
source code you must install it by downloading it from the following URL:
http://amfm.googlecode.com/files/amfm.zip. After you downloaded it extract it in a dedicated
folder (e.g. /usr/local/amfm). You do not need to run any configuration script or alter any AMFM
configuration file for the installation. If you are on a *nix system check that you have a file
named amfm in the folder you extracted AMFM to, then run to following command to make the
file executable: chmod 755 amfm. That‟s it! You are ready to start, make sure you always run
amfm command when you are in the folder you installed it in.
Hello World Program
We will start by a simple program that plays 4 notes with a piano.
Team Mondegreen - AMFM project report 11
seed helloworld
{
PIANO;
F; G; A; F;
}
start
{
play(helloworld, 1, 1);
}
How to run the program depends on the operating system used. In our example we will refer to a
*nix-based system such as: Unix, Linux, OSX, or cygwin. First, save this program to a file, for
example HelloWorld.amfm, note that you can name the file containing your code any name you
like but for clarity it is better to give it a meaningful name. To compile the program, execute the
command (from a terminal window): „amfm HelloWorld.amfm‟. If there were no typos, the
program will silently compile and generate a java class file: HelloWorld.class. If the class is ran
using the command java HelloWorld, a file named HelloWorld.wav will be created in the current
folder. Play this file in your favorite music player software to hear the results. You can also find
it in the following link: http://amfm.googlecode.com/files/helloworld.mid.
Now for some explanations about the program: An AMFM program at its most rudimentary level
must include a seed definition and start function definition that contains at least one statement
that specifies how to play that seed. A seed describes one measure of music in a simple
quadruple (4/4) time signature. In the hello world program above we see one seed with the name
helloworld. After the name and inside curly brackets we define the instrument for the seed and
the seed notes. The first line in our definition is “PIANO”, which sets the instrument that plays
Team Mondegreen - AMFM project report 12
the notes defined below in the seed. Only one instrument can be defined for a seed and it must be
defined as the first line of the seed followed by a semicolon. Take a notice that PIANO should be
all upper case letters otherwise a syntax error will be thrown during compilation. Following the
instrument definition we‟ll define the notes that are written in the classical notation, A-G, (not
the solfège notation). Like the instrument definition, a semicolon follows each note. Take a look
at the notes listed. You have probably guessed this seed describes 4 notes. If the seed notes were
to appear on a musical score, it would look like this:
Notice each note has automatically been set as quarter notes in the fourth octave and with a
volume of mezzo forte. We will discuss ways to define more fine-grained notes later. The
program automatically uses The Acoustical Society of America‟s standard octave designation
system (i.e. the 4th octave begins with middle C). After the seed definition we see the function
start. You may see it as the main function if you are familiar C or Java. The start function will
contain other function calls that will dictate how your music piece is produced from the seeds.
Unlike other programming languages that let you define your own functions, AMFM has nine
built in functions, start is one of them, and is a special function since the program begins
executing at the first statement in start. Our start function contains only one statement:
play(helloworld, 1, 1);
This statement is a call to a function named play. As we can see a function call contains the
function name (play) followed by a list of arguments separated by commas in parenthesis. The
function play is another built in AMFM function that simply plays a seed. We can see that it has
Team Mondegreen - AMFM project report 13
three arguments: first is the name of the seed to play. The second argument is the measure we
want to start playing the seed; note here that you count measures starting with one. The third
argument is the number of measures we want to play the seed for which should be at least one.
So the Hello World program plays the helloworld seed starting on measure 1 and for the length
of 1 bar. If there is no play (or other function as we will see later) function called for a seed, that
seed would never be part of the composition. Later on we will discuss creating partial measures
for such things as coming in on the 4th beat for an entrance. For now, create full measures with a
4 beats worth of notes. Now that you have a basic feel for the language construction, you should
see the simplicity behind it. In the following program we explore more features of the language
that allow you to refine the basic Hello World program.
Hello World Refined
seed helloworldrefined
{
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF; F4,1/4,MF; R,1/4;
}
start
{
play(helloworldrefined, 1, 1);
}
This program is very similar in structure to our hello world program from the previous section.
Yet you can notice few differences: first the seed now has the name helloworldrefined. Second,
the note unit has many new definitions; let‟s take a closer look at them. We can see that instead
Team Mondegreen - AMFM project report 14
of just a note letter we have a note letter followed by a number. This number designates which
octave the note should be played in. The note description continues with length as the next
parameter. Length is given in terms of musical notation of beats. (e.g. ¼ is a quarter note). A
quick scan tells us we have a quarter note, an eighth note, followed by another eighth, and finally
a quarter note. The last note descriptor consists of the dynamic (volume) of the note. We again
use the musical notation to indicate this. The seed that is described by the code would look like
this on a musical score:
To listen to it follow this link: http://amfm.googlecode.com/files/helloworldrefined.mid This
musical score version is identical to the seed definition in our hello world program.
Syntax Errors
seed hello worldrefined
{
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF; F4,1/4,MF;
}
start
{
play(hello worldrefined, 0, -1);
}
So far you have seen code that runs smoothly and perfectly in the AMFM language. It is time to
introduce you to some of the syntactic errors that might happen while writing a program. If you
Team Mondegreen - AMFM project report 15
are familiar with other programming languages, you will spot the first error: variable names must
be one word with no spaces. In this example we see that the seed name contains a space between
hello and world, this is invalid syntax and if you try to compile the program the compiler will
complain. Can you notice other errors? When we talked about the play function we said that the
start measure starts from one, and that the number of measures to play should be at least one. In
other words, the play function only handles positive numbers. This means that a negative length
will not be accepted as valid code. So we can see another two errors here. As an exercise try
fixing the errors till the program complies and produces the same result as the refined Hello
World program.
Beyond Hello World
Look at the following program:
seed piano1
{
PIANO; //5 bars of piano, 1 bar per line
R,4/4;
C4,1/2; G3,1/2;
A3,1/2; F3,1/2;
C4,1/2; G3,1/2;
C3,4/4;
}
seed flute1
{
FLUTE; //5 bars of flute, 1 bar per line
R,3/4; C5,1/8; D5,1/8;
E4,1/4; G4,1/4; D4,1/4; C4,1/8; D4,1/8;
E4,1/4; D4,1/8; C4,1/8; A3,1/8; C4,1/8; C4,1/8; D4,1/8;
Team Mondegreen - AMFM project report 16
E4,1/8; G4,1/8; D4,1/8; C4,1/8; B3,3/8; C4,1/8;
A3,4/4;
}
start
{
play(piano1, 1, 5);
play(flute1, 1, 5);
}
This program isn‟t the same one you saw in the first part of this tutorial. The first obvious new
complexity in this code is the number of seeds. The concept shouldn‟t be hard to grasp. Having
two seeds produces two different lines of music (as seen in a composer‟s score appearing below).
The two seeds will not play on the same line. You should note that while the names of the seeds
coincide with the declared instrument, this was only done as a styling design to improve the
program readability. It is not a language requirement - in fact you can name the seeds any names
you like containing numbers and letters (but not white spaces or reserved words!).
Do not let the number of notes scare you. Each line contains 1 bar. This is explained to you
inside the code after the instrument declaration. The seemingly prose structure of this sentence is
not read by the compiler because it is a comment! The double slash (//) will hide every character
after it until a newline is read. Comments are useful when programs become as complicated as
this one. You can remind yourself why you structured the notes the way you did. Knowing that
each line is a measure of music makes the block of notes easier to read. It also helps to remember
that between each note description there is a semicolon separating them.
The notes seem to be missing one thing don‟t they? There is no dynamic (volume) marking on
them. Remember that there are default settings for AMFM. In our first hello world program we
used all of the default notes settings. The default setting for dynamics is MF or the last set
Team Mondegreen - AMFM project report 17
volume of a previous note in that seed (if one exists). In the following code, all notes following
the first one would echo the F dynamic setting.
R,3/4,F; C4,1/8; D4,1/8;
It might seem awkward to read at first, but you‟ll be getting into the hang of it in no time. Or
perhaps you are wondering why there is an R in the place of a note. R is the symbol in AMFM
for a musical rest. As promised earlier, this is how you can purposely and meaningfully put
musical rests where you want. The same syntax applies for a rest. The only difference is if a
dynamic is set for the rest, an error will be thrown. There is no way to make a loud silence!
The two seeds produce musical score that looks like this (piano1 one is the top score line, flute1
is the two bottom lines):
Looks like a decent piece of music doesn‟t it? We now have multiple instruments playing
simultaneously. Please notice that in the score the bars of the two instruments are not visually
aligned, since each instrument note was generated separately (but in the piece itself they will be
aligned).
Here is another program that is almost similar, but when played is very different all because of a
change to the play arguments:
Team Mondegreen - AMFM project report 18
seed piano1
{
PIANO; //5 bars of piano, 1 bar per line
R,4/4;
C4,1/2; G3,1/2;
A3,1/2; F3,1/2;
C4,1/2; G3,1/2;
C3,4/4;
}
seed flute1
{
FLUTE; //5 bars of flute, 1 bar per line
R,3/4; C5,1/8; D5,1/8;
E4,1/4; G4,1/4; D4,1/4; C4,1/8; D4,1/8;
E4,1/4; D4,1/8; C4,1/8; A3,1/8; C4,1/8; C4,1/8; D4,1/8;
E4,1/8; G4,1/8; D4,1/8; C4,1/8; B3,3/8; C4,1/8;
A3,4/4;
}
start
{
play(piano1, 6, 5);
play(flute1, 1, 5);
}
Below is the musical score:
Team Mondegreen - AMFM project report 19
Though the instrument bars are not aligned visually if you follow them you can notice that no
two instruments are playing at any one time. But the essence of simultaneity is still there because
the other instrument (the piano1 seed) isn‟t exactly taking a break, it is playing rests for the first
five bars while the flute is playing (note that there‟s actually 6 bars of rest because one bar of rest
comes from the seed definition), and then the roles reverse and the flute is playing rests for five
bars (not shown in the score) while the piano is playing its notes. Also note that in the final piece
will hear the flute for the first five measures, then the piano will start playing but since its first
measure is a rest there will be silence on the sixth measure and the piano will be heard from the
seventh till the tenth measures.
One final comment about seeds regarding the note definitions concerns the length of the seed. A
seed can be any length. It does not have to be a full measure even though all of our examples
have seeds filling full measures (this is because it‟s easier to understand for beginners).
Transformations
seed piano1 {
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF; F4,1/4,MF;
}
start //play each transformation one after the other
{
SSpitch(piano1, 1, 4, FALSE);
SSrhythm(piano1, 5, 3, FALSE);
SSvolume(piano1, 8, 4, FALSE);
}
Team Mondegreen - AMFM project report 20
Now the real core and heart of AMFM comes into play. As the introduction to this tutorial
discussed, self-similarity patterns drive fractal composing. So you have to understand and
implement them to exploit AMFM full potential.
In your start function you see no play function. The play function is very simple; it only plays the
notes defined in the seed for the number of measures you define. If you haven‟t tested it yet, you
will find that play only repeats the seed over and over if you call it with more than one measure
to play (third argument). AMFM language uses three SS functions to produce the self-similarity
transformations and generate fractal compositions based on a single seed. A SS function will do
certain musical valid manipulations on the seed and also play them. A manipulation is much
more than a simple single tweak. The SS function which implements a manipulation applies it to
the entire seed and repeats itself.
These SS functions are all listed in the example above. Each one (pitch, rhythm, volume)
performs the manipulation their names suggest. The specific function methods are described
more in depth in the AMFM reference manual.
A SS function has the exact same parameters as the play function with the exception that a fourth
Boolean (TRUE/FALSE) parameter must be set. This fourth option will be explained in the next
section of the tutorial. For now keep the option at FALSE. In this manner, the SS functions will
loop after they complete a self-similarity cycle. The cycle of a SS function could be multiple
manipulations. For example in the code above, a pitch function will generate four measures of
music. The original measure is played, followed by three measures; each one of these measures
is the result of applying a self-similarity pitch manipulation to the measure preceding. So in our
example the first measure is the original seed, the second is the original seed after pitch
manipulation; the third is the second seed after applying the next pitch manipulation and so on.
Team Mondegreen - AMFM project report 21
Notice that the duration of the pitch function is only four measures. However, if we have defined
six notes in our seed, we would have six measures. Give it a try!
With the completion of this section in our tutorial, you are prepared to start writing some of your
own code and making your own fractal pieces. You have all the necessary information. The next
two sections cover some advanced topics about SS functions and can be completed at a later date
if you are anxious to write some code right now.
Multiple Transformations
seed piano1
{
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF; F4,1/4,MF;
}
start //play each transformation one after the other
{
SSpitch_volume(piano1, 1, 4, FALSE);
SSrhythm_volume(piano1, 5, 3, FALSE);
SSpitch_rhythm(piano1, 8, 4, FALSE);
SSall(piano1, 12, 4, FALSE);
}
Now we introduce the last of the nine functions that make up AMFM. You already know
what SS means; hence it‟s obvious these functions merely combine two self-similar
manipulations. With these new tools, you‟ll be able to play a fragment of music that has a pitch
and volume manipulation running on a seed. It gives you more freedom for creativity and
uniqueness. Having seen all AMFM functions, note that an AMFM program can only have up to
16 functions (any of the functions you have seen count as one).
Team Mondegreen - AMFM project report 22
Now that you have completed the last of the functions, we‟ll show you how you can use
them as pieces in your grand production. For example, take a seed that you have created. Run a
pitch and volume manipulation for a few measures on the seed. Then start from where you left
off and play a pitch and rhythm manipulations. To finish of the piece, run a rhythm and volume
manipulation making go softer and slower. You‟ve just completed an intro, main body, and exit
using the fractal functions. Congratulations!
Continuous Play
seed piano1
{
PIANO;
F4,1/4,MF; G4,1/8,F; A4,1/8,MF; F4,1/4,MF;
}
start
{
SSpitch(piano1, 1, 12, FALSE); //will loop for 12 bars
SSpitch(piano1, 13, 12, TRUE); //will continue to perform
//pitch transformations for 12 bars
}
To understand the fourth parameter, it is advisable that you have some understanding of fractal
composing. As described in the previous section, a FALSE option provides the looping behavior.
In other words, once the manipulation finished producing bars, if the re are still more bars left to
be played, it will go back to the original seed and play it. If there are more bars available it will
perform the same manipulations and play them.
The TRUE setting is really what this section of the tutorial is about. In the TRUE setting, once a
SS function completes the cycle, the remaining bars do not simply loop back to the seed. The
Team Mondegreen - AMFM project report 23
remaining bars are filled with the SS manipulation as if the last measure in the cycle was the
seed. This will produce no looping music especially if the seed itself is varied enough. The
TRUE settings allow for some unpredictability and it is a integral part of the fractal composing.
Combined with the SS function, this behavior specification allows you to write music with the
simple typing of a few words.
Below is the music score of a sample file that AMFM can put into mp3 file. You can choose to
directly implement the piece with a simple list of notes and the play function. Or you can try to
imitate the piece with seeds and SS functions. There‟s an obvious choice when using the AMFM
language.
Team Mondegreen - AMFM project report 24
Team Mondegreen - AMFM project report 25
Team Mondegreen - AMFM project report 26
Reference Manual
Introduction
AMFM is a language designed to support fractal music composition with a minimum of syntax
and programmatic overhead. Because of the nature of music composition in general, and fractal
music in particular, AMFM does not require many of the constructs that are present in other
general purpose programming languages that are designed primarily to implement algorithms
that act on data. A desirable side effect of this simplicity is that users who have no experience
with programming will find it easy to compose fractal music using AMFM, which is beneficial
since most musicians are not programmers. The user does not have to worry about variable
assignments or mutable data-structures. Instead, AMFM allows users to easily create and
manipulate basic units of fractal music, which are combined into the composition as a whole.
Composition Overview
To create a composition, users manipulate musical „seeds,‟ which are then transformed over
time based on one of the following: pitch, rhythm, or volume. The user can define seeds by
specifying the voice, or instrument, and a number of musical notes with duration and volume.
The user then manipulates these seeds via transforms – built in language functions that
modify the seeds over time.
Implementation
AMFM is designed so that the actual creation of music is transparent to the user – the user
Team Mondegreen - AMFM project report 27
only has to consider the fractal composition. The AMFM language core converts the user‟s
input into the eventual musical representation by performing transforms on the musical seeds
provided by the user. AMFM‟s output, a linear sequence of notes, may then be converted to
either notational form via MIDI or audio form via MP3 or WAV.
Lexical conventions
Comments
AMFM supports single line comments that begin with a double forward slash (//) and end with
the next newline
Whitespace
Whitespace, consisting of spaces, tabs, and newlines, is ignored, with the exception of
newline terminated comments.
Reserved Words
Reserved words are integral to the language and may not be used as identifiers. The
following words are reserved:
seed start play SSpitch SSrhythm SSvolume
SSpitch_volume SSrhythm_volume SSpitch_rhythm SSall b
bb x #
All notes and accidental forms
All fractions
End of Statement
A semicolon terminates all statements in AMFM language.
Team Mondegreen - AMFM project report 28
Tokens
Identifiers
Identifiers for variables are alphanumeric and can contain any combination of ASCII numerals
and non-special characters. It must begin with a lowercase letter
Boolean Literals
Boolean literals have the values: TRUE or FALSE
Note Literals
Note literals describe musical notes (the letters A-G,) and take the form of the note, followed
by optional sharp (#), double sharp (x), flat (b) or double flat (bb), then the standard octave
number. The letter R denotes a rest.
Example: A sharp in the third octave
A#3
Note literals are only parsed as such inside of seeds
Beat Literals
Beat literals describe a musical interval. They take the form of a fraction of a whole note,
expressed by an integer, a forward slash, followed by an integer. They can also be a single
integer representing that many whole measures.
Examples:
Whole note literal: 4/4 or 1
Quarter note literal: 1/4
Team Mondegreen - AMFM project report 29
Eighth note literal: 1/8
Beat literals are only parsed as such inside of seeds.
Volume Literals
Volume literals describe the dynamics of a note. AMFM recognizes the following volume
literals:
PPP PP P MP MF F FF FFF
These correspond to the musical notation for dynamics.
Volume literals are only parsed as such inside of seeds
Instrument Literals
Instrument literals describe instruments. The valid instruments are
PIANO BASS CELLO VIOLIN VIOLA FLUTE
Instrument literals are only parsed as such inside of seeds
Scope
AMFM is statically scoped, and has only a global scope for seed variables. Literals,
however, do depend on scope, and are only visible inside of seeds
Data Types
Note Unit
A note unit is not an explicitly defined data-type, but does function as such. A note unit consists
Team Mondegreen - AMFM project report 30
of a note literal, followed by an optional beat literal, followed by an optional volume literal,
separated by commas and terminated by a semicolon.
Example note unit:
Fb4, 1/4, MF;
If the volume literal is not specified, the values default to either the previously used value, or if
this is the first note unit in the seed, the global default (which is MF). If the note duration is not
specified (in which the volume must also remain unspecified), it defaults to ¼ (not the
previously assigned note duration).
Seed
Seed is the fundamental (and only) data-type in AMFM. A seed is a unit of music specified by
note, beat, and volume literals. It also includes information about instruments.
Curly braces delimit seeds.
The first statement in the seed is optional. The first is the instrument declaration.
After the first statement
Example seed with all options: seed
seedexample
{
PIANO;
A4, 1/2, MF; B4,1/2,MF;
}
AMFM will always operate on the chromatic scale.
Start Block
Once seeds are defined, they may be played and manipulated by functions. All such
functions must be called inside of the start block. The start block can contain up to 16
Team Mondegreen - AMFM project report 31
function calls4. The block is described by the start keyword followed by curly braces. The
start block must appear as the last thing in the program after all seeds are defined.
Example:
start
{
play(exampleseed, 1, 1);
}
Functions
AMFM does not have user-defined functions, but does include a number of functions
integrated into the language. Functions calls are defined by the name of the function,
followed by a comma-delimited list of parameters inside of parentheses. A semicolon
terminates the function call, as with other statements. There is a maximum of 16 functions
allowed in any one AMFM program. AMFM includes the following functions:
play(seed, startbar, duration)
play simply plays the seed from the specified bar for the specified duration, looping if
necessary. No transforms are performed.
SSpitch(seed, startbar, duration, continuousplay)
The SSpitch function plays notes, much the same way that the play function plays notes.
4
This is due to midi limitation of 16 channels playing. While not all 16 functions are playing
simultaneously channels still have to be created. Supporting more than 16 function calls based on
the bars they are actually played at will be a good feature to add in the future.
Team Mondegreen - AMFM project report 32
However, instead of simply looping the seed, SSpitch will generate new bars with notes based
on the pitch transformation.
The pitch transformation first performs an analysis on the seed notes to deduce the relationships
between the seed notes. A pitch relationship describes how one note transitions to the next note,
for example two steps higher in pitch or one step lower in pitch. A pattern is then created, which
is a collection of relationships. If the seed contains two notes, there will be one relationship
deduced between the two of them. If the seed contains three notes, there will be two
relationships in the pattern. Therefore, if the seed contains n notes, there will be n-1
relationships in the pattern. The pitch transformation then takes this pattern and applies it to the
seed notes to generate a new collection of notes that are shifted by the appropriate number of
steps. This self-similar generation of notes produces a pitch-based musical fractal.
The example below will demonstrate how the pitch transformation deduces a pattern from a
seed and then generates a musical fractal.
The figure above shows an example of a seed. With regard to only pitch, this seed will
produce a pattern that contains three relationships: one step up, one step up, and two steps
down. SSpitch will then apply this pattern by shifting all the notes
In the previous bar up one step, then shifting all the notes again by another one step, and
then finally shifting all the notes down by two steps. The first transformation operates on
the seed. The resulting music fractal consists of four bars in total, with the first bar
containing the seed notes and the following three bars each containing the shifted notes
Team Mondegreen - AMFM project report 33
for each particular relationship in the pattern.
The figure above contains four bars of notes. The first bar is simply the seed. The second bar has
undergone the first pitch transformation, which is the previous bar (the seed) shifted one step up.
The third bar is the second bar shifted one step up and the fourth bar is the third bar shifted two
steps down.
The first parameter of the SSpitch function is seed. seed references the seed that has been
defined by the user in separate seed blocks using note syntax.
The second parameter of the SSpitch function is startbar. startbar is any integer 1 or greater
that determines on which bar the transformation will begin.
The third parameter of the SSpitch function is duration. duration is any integer 1 or greater
that determines the length in bars for which the transformation will play. Once the duration is
up, the transformation will immediately stop playing, regardless of whether or not the
transformation has finished.
The fourth parameter of the SSpitch function is continuousplay. continuousplay is a boolean
that is either TRUE or FALSE, with a default value of FALSE.
When continuousplay is set to FALSE, once the transformation completes, SSpitch will simply
loop the generated notes until the duration has been reached. When continuousplay is set to
TRUE, once the transformation has finished generating notes through the pattern, it will loop
Team Mondegreen - AMFM project report 34
back to the first relationship in the pattern and continue performing subsequent transformations
using the pattern until the duration has been reached.
SSrhythm(seed, startbar, duration, co ntinuousplay)
The SSrhythm function is a built-in function in AMFM that plays notes, much the same way
that the play function plays notes. However, instead of simply looping the seed, SSrhythm will
generate new bars with notes based on the rhythm transformation.
The rhythm transformation first performs an analysis on the seed notes to deduce the
relationships between the seed notes. A rhythm relationship describes the difference in length of
a note compared to the next note; for example, a note that is 1/4 in length is two times greater in
length than a note that is 1/8 in length. A pattern is then created, which is a collection of these
length relationships. If the seed contains two notes, there will be one relationship deduced
between the two of them. If the seed contains three notes, there will be two relationships in the
pattern. Therefore, if the seed contains n notes, there will be n-1 relationships in the pattern.
The rhythm transformation then takes this pattern and applies it to the seed notes to generate a
new collection of notes that are either all shortened in length or all elongated in length based on
the particular relationship. This self-similar generation of notes produces a rhythm-based
musical fractal.
The example below will demonstrate how the rhythm transformation deduces a pattern from
a seed and then generates a musical fractal.
Team Mondegreen - AMFM project report 35
The figure above shows an example of a seed. With regard to only rhythm, this seed will produce
a pattern that contains three relationships: twice as short, same length, and twice as long. This is
because the first note is a quarter note (length of 1/4) while the second note is an eight note
(length of 1/8), the third note is also an eight note, and the fourth note is back to a quarter note.
SSrhythm will then apply this pattern by reducing the length of all the notes in the previous by a
factor of 2, then maintaining the same length for all notes as the previous bar, and then finally
increasing the length of all the notes by a factor of 2. The first transformation operates on the
seed. The resulting music fractal consists of three bars in total, with the first bar containing the
seed notes, the second bar containing two sets of shorter-lengthed generated notes, and the third
bar containing the notes from the second bar increased by a factor of
The figure above contains three bars of notes. The first bar is simply the seed. Then, the pattern is
pattern is applied by SSrhythm to generate a string of notes with all their lengths halved. Because
of this, the notes do not fill up the entire bar. The next transformation uses the "same length as
previous bar" relationship, so a string of notes is once again generated, which fills the remainder
of the second bar. The third bar is transformed by increasing the length of the notes back to the
Team Mondegreen - AMFM project report 36
original length.
The first parameter of the SSrhythm function is seed. seed references the seed that has been
defined by the user in separate seed blocks using note syntax.
The second parameter of the SSrhythm function is startbar. startbar is any integer 1 or greater
that determines on which bar the transformation will begin.
The third parameter of the SSrhythm function is duration. duration is any integer 1 or greater that
determines the length in bars for which the transformation will play. Once the duration is up, the
transformation will immediately stop playing, regardless of whether or not the transformation has
finished.
The fourth parameter of the SSrhythm function is continuousplay. continuousplay is a boolean
that is either TRUE or FALSE, with a default value of FALSE. When continuousplay is set to
FALSE, once the transformation completes, SSrhythm will simply loop the generated notes
until the durationhas been reached. When continuousplay is set to TRUE, once the
transformation has finished generating notes through the pattern, it will loop back to the first
relationship in the pattern and continue performing subsequent transformations using the
pattern until the duration has been reached.
SSvolume(seed, startbar, duration, continuousplay)
The SSvolume function is a built-in function in AMFM that plays notes, much the same way
that the play function plays notes. However, instead of simply looping the seed, SSvolume will
generate new bars with notes based on the volume transformation, which is perhaps the easiest
transformation.
The volume transformation first performs an analysis on the seed notes to deduce the
Team Mondegreen - AMFM project report 37
relationships between the seed notes. A volume relationship describes the difference in volume
of a note compared to the next note; for example, a note that has a volume of F is one step
louder in volume than a note that has a volume of MF. A pattern is then created, which is a
collection of these volume relationships. If the seed contains two notes, there will be one
relationship deduced between the two of them. If the seed contains three notes, there will be two
relationships in the pattern. Therefore, if the seed contains n notes, there will be n-1
relationships in the pattern. The rhythm transformation then takes this pattern and applies it to
the seed notes to generate a new collection of notes with varying volumes based on the pattern.
This self-similar generation of notes produces a volume-based musical fractal.
The example below will demonstrate how the volume transformation deduces a pattern from
a seed and then generates a musical fractal.
The figure above shows an example of a seed. With regard to only volume, this seed will
produce a pattern that contains three relationships: one step up in volume, one step down in
volume, and same volume. This is because the first note is MF, while the second note is F
(denoted by the > shaped symbol), which is one step higher in volume. The third note and
fourth note return to MF volume. SSvolume will then apply this pattern by varying the
volume of the generated notes by the relationships specified in the seed. The first
transformation operates on the seed. The resulting music fractal consists of four bars in total,
with the first bar containing the seed notes, the second bar containing the notes of the first bar
Team Mondegreen - AMFM project report 38
raised in volume, the third bar containing the notes from the second bar lowered in volume,
and the fourth bar containing notes with the same volume as the notes in the third bar.
The figure above contains four bars of notes. The first bar is simply the seed. Then, the
pattern is applied by SSvolume to generate a string of notes with one step up in volume,
which is why we see the volume of F for that one bar. The next transformation uses the "one
step down in volume" relationship, so a string of notes is once again generated at the volume
of MF. The fourth bar maintains the same volume as the previos bar.
The first parameter of the SSvolume function is seed. seed references the seed that has been
defined by the user in separate seed blocks using note syntax.
The second parameter of the SSvolume function is startbar. startbar is any integer 1 or greater
that determines on which bar the transformation will begin.
The third parameter of the SSvolume function is duration. duration is any integer 1 or greater that
determines the length in bars for which the transformation will play. Once the duration is up, the
transformation will immediately stop playing, regardless of whether or not the transformation has
finished.
The fourth parameter of the SSvolume function is continuousplay.
continuousplay is a boolean that is either TRUE or FALSE, with a default value of FALSE.
Team Mondegreen - AMFM project report 39
When continuousplay is set to FALSE, once the transformation completes, SSvolume will
simply loop the generated notes until the durationhas been reached. When continuousplay is
set to TRUE, once the transformation has finished generating notes through the pattern, it will
loop back to the first relationship in the pattern and continue performing subsequent
transformations using the pattern until the duration has been reached.
SSpitch_volume(seed, startbar, duration, continuousplay)
The SSpitch_volume function is a built-in function in AMFM that plays notes, much the same
way that the play function plays notes. However, instead of simply looping the seed,
SSpitch_volume will generate new bars with notes based on the volume and pitch transformation,
which will sound as if a pitch manipulation and volume manipulations were running on the seed
at the same time.
To get a sense of each of these manipulations, look at the SSpitch and then SSvolume sections of
this reference manual.
The first parameter of the SSpitch_volume function is seed. seed references the seed that has
been defined by the user in separate seed blocks using note syntax.
The second parameter of the SSpitch_volume function is startbar. Startbar is any integer 1 or
greater that determines on which bar the transformation will begin.
The third parameter of the SSpitch_volume function is duration. Duration is any integer 1 or
greater that determines the length in bars for which the transformation will play. Once the
duration is up, the transformation will immediately stop playing, regardless of whether or not
the transformation has finished.
The fourth parameter of the SSpitch_volume function is continuousplay. continuousplay is a
boolean that is either TRUE or FALSE, with a default value of FALSE. When continuousplay
Team Mondegreen - AMFM project report 40
is set to FALSE, once the transformation completes, SSpitch_volume will simply loop the
generated notes until the duration has been reached. When continuousplay is set to TRUE, once
the transformation has finished generating notes through the pattern, it will loop back to the first
relationship in the pattern and continue performing subsequent transformations using the pattern
until the duration has been reached.
SSrhythm_volume(seed, startbar, duration, continuousplay)
The SSrhythm_volume function is a built-in function in AMFM that plays notes, much the same
way that the play function plays notes. However, instead of simply looping the seed,
SSrhythm_volume will generate new bars with notes based on the volume and rhythm
transformation, which will sound as if a rhythm manipulation and volume manipulations were
running on the seed at the same time.
To get a sense of each of these manipulations, look at the SSrhythm and then SSvolume sections
of this reference manual.
The first parameter of the SSrhythm_volume function is seed. seed references the seed that has
been defined by the user in separate seed blocks using note syntax.
The second parameter of the SSrhythm_volume function is startbar. Startbar is any integer 1 or
greater that determines on which bar the transformation will begin.
The third parameter of the SSrhythm_volume function is duration. Duration is any integer 1 or
greater that determines the length in bars for which the transformation will play. Once the
duration is up, the transformation will immediately stop playing, regardless of whether or not
the transformation has finished.
The fourth parameter of the SSrhythm_volume function is continuousplay. continuousplay is a
boolean that is either TRUE or FALSE, with a default value of FALSE. When continuousplay
Team Mondegreen - AMFM project report 41
is set to FALSE, once the transformation completes, SSrhythm_volume will simply loop the
generated notes until the duration has been reached. When continuousplay is set to TRUE, once
the transformation has finished generating notes through the pattern, it will loop back to the first
relationship in the pattern and continue performing subsequent transformations using the pattern
until the duration has been reached.
SSpitch_rhythm(seed, startbar, duration, continuousplay)
The SSpitch_rhythm function is a built-in function in AMFM that plays notes, much the same
way that the play function plays notes. However, instead of simply looping the seed,
SSpitch_rhythm will generate new bars with notes based on the pitch and rhythm transformation,
which will sound as if a rhythm manipulation and pitch manipulations were running on the seed
at the same time.
To get a sense of each of these manipulations, look at the SSrhythm and then SSpitch sections of
this reference manual.
The first parameter of the SSpitch_rhythm function is seed. seed references the seed that has
been defined by the user in separate seed blocks using note syntax.
The second parameter of the SSpitch_rhythm function is startbar. Startbar is any integer 1 or
greater that determines on which bar the transformation will begin.
The third parameter of the SSpitch_rhythm function is duration. Duration is any integer 1 or
greater that determines the length in bars for which the transformation will play. Once the
duration is up, the transformation will immediately stop playing, regardless of whether or not
the transformation has finished.
The fourth parameter of the SSpitch_rhythm function is continuousplay. continuousplay is a
boolean that is either TRUE or FALSE, with a default value of FALSE. When continuousplay
Team Mondegreen - AMFM project report 42
is set to FALSE, once the transformation completes, SSpitch_rhythm will simply loop the
generated notes until the duration has been reached. When continuousplay is set to TRUE, once
the transformation has finished generating notes through the pattern, it will loop back to the first
relationship in the pattern and continue performing subsequent transformations using the pattern
until the duration has been reached.
SSall (seed, startbar, duration, continuousplay)
The SSall function is a built-in function in AMFM that plays notes, much the same way that the
play function plays notes. However, instead of simply looping the seed, SSall will generate new
bars with notes based on the pitch, rhythm, and volume transformation, which will sound as if a
rhythm, pitch, and volume manipulations were running on the seed at the same time.
To get a sense of each of these manipulations, look at the SSrhythm, SSpitch, and SSvolume
sections of this reference manual.
The first parameter of the SSall function is seed. seed references the seed that has been
defined by the user in separate seed blocks using note syntax.
The second parameter of the SSall function is startbar. Startbar is any integer 1 or greater that
determines on which bar the transformation will begin.
The third parameter of the SSall function is duration. Duration is any integer 1 or greater that
determines the length in bars for which the transformation will play. Once the duration is up,
the transformation will immediately stop playing, regardless of whether or not the
transformation has finished.
The fourth parameter of the SSall function is continuousplay. continuousplay is a boolean that is
either TRUE or FALSE, with a default value of FALSE. When continuousplay is set to FALSE,
Team Mondegreen - AMFM project report 43
once the transformation completes, SSall will simply loop the generated notes until the duration
has been reached. When continuousplay is set to TRUE, once the transformation has finished
generating notes through the pattern, it will loop back to the first relationship in the pattern and
continue performing subsequent transformations using the pattern until the duration has been
reached.
Team Mondegreen - AMFM project report 44
Grammar
Note: grammar rules are in the ANTRL format in which non-terminals as lower case words and
TOKENS (terminals) as upper case. Colors are added for readability.
program : seed* start_func?
// Seed rules
seed : 'seed' ID '{' INSTRUMENT ';' note_unit+ '}'
note_unit : note ( ',' duration ( ',' volume)? )? ';'
duration: FRACTION | number;
volume : VOLUME_LEVELS_MINUS_F | 'F';
note : note_letter octave? ;
note_letter: NOTELETTERS_WITH_ACCIDENTAL_MINUS_F |
'F'ACCIDENTAL?;
octave: ONE_TO_NINE;
// Start function
start_func: START '{' function* '}'
function: (play | ss_func) ';';
play: PLAY '(' func_params[$PLAY.text] ')'
ss_func: ss_func_name '(' ss_func_params[$ss_func_name.text] ')'
ss_func_name: (SS_PITCH | SS_VOLUME | SS_RHYTHM |
SS_PITCH_VOLUME | SS_PITCH_RHYTHM | SS_RHYTHM_VOLUME | SS_ALL);
ss_func_params[String func_name]: func_params[$func_name] ','
BOOLEAN;
func_params[String func_name]: ID ',' start_bar ',' num_of_bars
start_bar: number ;
num_of_bars: number ;
number : ONE_TO_NINE | TEN_AND_UP;
Team Mondegreen - AMFM project report 45
// Tokens
// Functions
START: 'start';
PLAY: 'play';
SS_PITCH : 'SSpitch';
SS_VOLUME: 'SSvolume';
SS_RHYTHM: 'SSrhythm';
SS_PITCH_VOLUME: 'SSpitch_volume';
SS_PITCH_RHYTHM: 'SSpitch_rhythm';
SS_RHYTHM_VOLUME: 'SSrhythm_volume';
SS_ALL: 'SSall';
COMMENT : '//'(~('\n'|'\r'))*('\n'|'\r'('\n')?)? {skip();};
// Notes
INSTRUMENT : 'PIANO' | 'VIOLIN' | 'CELLO' | 'TRUMPET' | 'VIOLA'
| 'FLUTE';
NOTELETTERS_WITH_ACCIDENTAL_MINUS_F : ('A'..'E' |
'G')ACCIDENTAL? | 'F'ACCIDENTAL ;
REST: 'R';
VOLUME_LEVELS_MINUS_F : 'PPP' | 'PP' | 'P' | 'MP' | 'MF' | 'FF'
| 'FFF';
fragment
ACCIDENTAL : ('#' | 'b' | 'bb' | 'x');
BOOLEAN : 'TRUE' | 'FALSE';
ID : ('a'..'z')('a'..'z'|'A'..'Z'|'0'..'9')* ;
FRACTION : (ONE_TO_NINE|TEN_AND_UP)'/'(ONE_TO_NINE|TEN_AND_UP);
ONE_TO_NINE: '1'..'9';
TEN_AND_UP: ONE_TO_NINE('0'..'9')+;
WS : (' '|'\t' | '\n' | '\r')+ {skip();};