Welcome to the Polyfoni User-Manual. The expected time-to-read is 20-25 minutes.
Alternatively, you can watch the official tutorial series on YouTube.
(Skip this if already familiar with Polyfoni).
Polyfoni is a desktop application for generating music from mathematical expressions. This is done by specifying expressions for three parameters – pitch, duration, and rest – along the timeline.
The user can select different expressions across different intervals, thus creating varying patterns in the music. This process is repeated for every desired melody which means that all melodies are generated independently from eachother.
To allow for coherence between melodies, the user can select which harmony each melody should have across a certain interval. At the bottom of the timeline, the user can view the resulting harmonies of the overlapping melodies, making the process of harmonization easy.
In Polyfoni, a voice is a container for everything that goes into generating a single melody. A melody being a number of sequential notes and rests.
An example of two melodies created with Polyfoni.
“Then what goes into generating a melody?”, you may ask. At its most basic, it is the four parameters – pitch, duration, rest, and harmony – that were mentioned in the introduction.
Each of these parameters are represented by a track in the voice. Essentially, a voice is just a collection of tracks which are used to generate and display a melody.
This is the voice from which the first melody was created.
Indicated with red is the Pitch, Duration, Rest, and Harmony tracks.
Each track plays a different role in the generation of the melody, except the first track which is used to display the resulting melody.
Indicated with red is the Output track.
The four tracks – pitch, duration, rest, and harmony – are grouped together in a group named “Framework”. There is also the “Decoration” group.
Let’s forget about the “Decoration” group for the time being. Both groups will be explained in more depth later in this document.
To specify what patterns to use for the different parameters, you create items on the tracks. An item is an interval with some data associated with it. In the case of the Pitch, Duration, and Rest tracks, the data associated with each item will be an expression (plain text). In the case of the Harmony track, the items will contain scales.
An example of an item.
You create items by highlighting one or more tracks across the desired interval and then pressing Insert on your keyboard.
To edit the data of an item, click the item you want to edit. At the bottom of the window, an editor will appear for the clicked item.
The type of data an item contains depends on which track it is placed on. In Polyfoni, there are two item types: Scale Items and String Items.
Next, we will go over the kinds of data each of these item types contain.
Polyfoni uses a binary system for representing scales. All that means is that every possible scale pattern is represented by a unique number, a.k.a. decimal.
When you click a Scale Item, you will be met by the scale editor at the bottom of the window.
You can select a scale by toggling which pitches should be included by clicking on the pitch names.
Indicated with red are the pitch names.
Or you can select a scale by its root and decimal. For example, the decimal 145 corresponds to the major triad scale pattern. If we select the pitch of C as the root, we have got ourselves a C Major Triad scale.
Indicated with red are the root and decimal.
All well and good. If you want to know more about this binary system for representing scales, I can highly recommend reading A study of musical scales by Ian Ring.
You can enter any text into String Items but if not a valid Python expression, it will yield an error and not generate anything.
An example of an invalid expression.
To further complicate things, expressions are expected to evaluate to certain types of values depending on which track the containing item lives on.
For instance, expressions of items on the Pitch and Duration tracks are expected to evaluate to a number whereas expressions of items on the Rest track are expected to evaluate to a boolean.
Some expressions that work on one track, do not work on other tracks.
Expressions are Python code that cannot contain variable declarations.
For example,
my_variable = 2 + 2
is not a valid expression whereas
2 + 2
is valid.
Due to Python’s simple syntax, most expressions will be indistinguishable to regular math expressions.
abs
all
any
divmod
filter
len
list
map
max
min
pow
range
reversed
round
slice
sorted
sum
Additionally, all functions and constans in the Python math module are also available.
Check out Python operators and Python math module if you're unfamiliar with these.
The Framework group is responsible for generating the broadest patterns of the melody. This we might call the melody’s skeleton, contour, or framework.
To start off with, it’s important to mention that – in the Framework group – a certain interval has to be filled with valid items on all tracks for the framework to generate across that interval.
We will now go over each track in the Framework group and their individual role in the generation of the framework.
Items on the Duration track are responsible for determining the
durations of the notes in the melody. Expressions must evaluate to a
single number. If the number is negative, it will be turned positive.
Additionally, the number will be quantized to the nearest common
duration value. Examples of possible durations are: 0.125
,
0.25
, 0.5
, 1
, 2
, and
4
.
For a given item on the Duration track, the specified expression is evaluated until the sum of the results is greater than or equal to the length of the item.
Each time the duration item gets evaluated, it yields the value
1
. This results in eight notes being generated to
cover the duration item.
If we set the duration expression to
0.5
, it takes 16 notes to cover the duration item.
Items on the Pitch track are (together with items on the Harmony track) responsible for determining the pitches of the notes in the melody.
For every note that begins within a given item, that item’s expression gets evaluated. The result of that evaluation determines the note’s pitch.
Expressions must evaluate to a number. This number will be rounded to the nearest integer. This integer then gets converted to pitch as a scale degree of the scale specified below the note on the Harmony track.
Even though the pitch item’s expression evaluates to
0
for every note, the pitch of the notes change halfway through
because the harmony changes.
Items on the Rest track are responsible for determining whether a note is a rest or not. Notes that are rests will not be visible nor audible.
As for the Pitch track, an item on the Rest track affects the notes that begin within it.
Expressions must evaluate to a boolean (True
or
False
). If True
, the note will be interpreted
as a rest. If False
, the note will be interpreted normally.
Where rest evaluates to True
, the notes become rests.
The Harmony track is tightly coupled with the Pitch track and so we have already covered it there. But to clarify, the scale that will be used to interpret a note’s pitch is determined by the scale item that the note begins within.
Now, you might wonder how notes that begin within the same items can end up with different pitches, durations, and only some become rests.
This is possible due to Polyfoni exposing each note’s index to the
expressions. What this means is that you can use a special variable
named x
. When expressions are evaluated for a given note,
x
will be set equal to the index of the note within the
item containing the expression.
So, for the first note within an item,
x
will be zero. For the second, x
will be one.
For the third, x
will be two. And so on…
The easiest demonstration of this is simply using
x
as the pitch of the melody. As you can see, this creates
a infinitely rising melody.
On the other hand, if we use -x
, the melody will be
infinitely falling.
Now, we can combine x
with our usual math operators and
functions to create more interesting patterns.
For example, if we want to avoid our melody being infinitely
rising/falling, we can use the modulo operator (%
). This
will make it repeat after a certain number of notes.
Or we can insert x
into the sin
or
cos
functions to create a wavy melody.
So far, you’ve learned about:
With the knowledge you’ve gained so far, you should be able to create simple melodies in Polyfoni.
Next up, we will be explaining the Decoration group.
Although the melodies resulting from the Framework group alone can be quite interesting, we might want to add something more. This is where the Decoration group comes in.
In Polyfoni, decoration is an umbrella term for any musical embellishments and ornaments. Examples of decorations in traditional western music include passing tones, appogiaturas, and suspensions.
A decoration consists of one or more notes. The pitches of these notes are generated relative to the pitch of the note before the decoration and/or the pitch of the note after the decoration.
In Polyfoni, this “relativity” is not enforced. In theory, you can create decorations which are independent from the note before and after the decoration. Whether or not this is a decoration at all is another question.
What characterizes all Polyfoni decorations though is that they each appear between two notes generated by the Framework group. That is, between every two Framework notes a decoration can be generated.
Items on the Pitches track are responsible for determining the number of notes in the decoration and their pitches. (Yes, decorations can consist of multiple notes!)
Expressions on this track must evaluate to an integer, a list of integers, or None. The number of returned integers determines the number of notes in the decoration. If None or an empty list is returned, no decoration will be made.
Because decorations like passing tones, appogiaturas, etc. are quite long and tedious to express using Python, they have been built into Polyfoni.
This means you can use builtins such as
PASSING_TONE
in items on the Pitches track to generate
passing tones without having to formulate the expression yourself.
Here’s the full list of builtins appropriate for use on the Pitches track:
PASSING_TONE
UPPER_NEIGHBOR_TONE
LOWER_NEIGHBOR_TONE
APPOGIATURA
ESCAPE_TONE
SUSPENSION
ANTICIPATION
A basic melody without any decorations.
The same melody but with decorations, using the builtin
PASSING_TONE
.
(The Framework group has been collapsed)
We can use multiple builtins in a single expression to alternate between different decoration types.
Melody decorated with alternating passing tones and appogiaturas using Python’s ternary operator.
Melody decorated with alternating passing tones, appogiaturas, and escape tones using Python’s list indexing.
Items on the Fraction track are optional. If no item is specified, the
default value of 0
will be used instead.
Items on the Fraction track are responsible for determining the duration of the decoration relative to the duration of the previous Framework note. Expressions on this track must evaluate to a number. Results are rounded to nearest integer.
If the result is 0
, the duration of the previous Framework
note will be split evenly between the previous Framework note and the
decoration. Subsequently, each note of the decoration will get an even
share of the duration reserved for the decoration.
Each decoration consumes half of the duration of the previous
Framework note when fraction evaluates to
0
.
If the fraction evaluates to 1
, the duration will be shared
1/3 and 2/3 between the previous Framework note and the decoration.
Each decoration consumes 2/3 of the duration of the previous
Framework note when fraction evaluates to
1
.
If the result is -1
, the duration will be shared 2/3 and
1/3 between the previous Framework note and the decoration. That is,
negative results assign the bigger part to the previous Framework note
instead of the decoration.
Each decoration consumes 1/3 of the duration of the previous
Framework note when fraction evaluates to
-1
.
Fraction can be as high or low a number as wanted unless the produced
notes have a smaller duration than the minimum allowed duration of
0.03125
. In that case, no decoration is made.
Items on the Skip track are optional. If no item is specified, the
default value of False
will be used instead.
Items on the Skip track are responsible for determining whether a
decoration should be skipped. Expressions must evaluate to a boolean
(True
or False
). If True
, the
decoration is skipped. If False
, the decoration is
preserved.
An example of using the Skip track to skip a decoration.
Items on the Harmony track are optional. If no item is specified, the
default value of
A-4095
is used instead.
Items on the Harmony track are used to convert the Pitches track results to pitches in the specified scale.
Decorations use the scale of the item that the previous Framework note begins within.
An example of limiting the pitches of decorations to the C Major scale.
As with the Framework group, the variable
x
is also exposed to expressions in the Decoration group.
Here, x
is the index of the decoration within the item
containing the expression.
Additional to x
, expressions in the Decoration group have
two more variables available for use: prev_degree
and
next_degree
.
You do not need to understand these variables to be able to create decorations. But just understand that they are what enables the builtin decorations to generate relative to the previous and/or next Framework note.
You have now learned the fundamentals of Polyfoni, including voices, tracks, items, the Framework group, and the Decoration group.
This user-manual should have given you a solid starting point from which to grow. And hopefully have inspired you to further explore music composition in Polyfoni!
Some topics have deliberately been left out of this user-manual for the sake of brevity. These include the Tempo track, the Harmonic Sum track, stuff like changing instruments, and how to add/delete voices.
Did you feel that anything was lacking? Let me know what you think.