Guido
Word Music
This is an implementation of one of the oldest known algorithmic music
processes.
It is rule based, not recombinatorial. Each vowel is allocated a pitch.
This implementation is not strict (as the original was designed for Latin
texts) but has been adapter to Roman languages and modern tonal sensibilities.
It is quite intriguing how close this process is the Arvo Pärt's
compositional processes! (Read about it in Hiller's book on Pärt.)
The interface:
This demo is a realisation of Mozart's design
in jMusic by Andrew Troedson.
Click here to view source part
1.
Click here to view source
part 2.
To hear the result play the Quicktime movie
below.
Andrew Troedson's comments:
An Overview
Based on Guido d'Arezzo's lookup chart for generating pitches from syllables
(ca. 1000 A.D.), this melody generation tool creates a monophonic phrase
by extrapolating from a given text. A set of rules (see Table 2.1 below)
is used to select note pitches depending on the vowels found in the text.
Although d'Arezzo's original intention was simply to provide an approximate
guide from which a composer could make selections to fit his/her taste,
this tool automates the process, and itself chooses from the given note
options.
As well as this, the wordMusic tool sets the selected notes to a rhythm
dependant on the number of consonants between each vowel (see Table 2.2).
Table 2.1: The note pitch value options assigned
by wordMusic to each vowel
g2 |
a2 |
b2 |
c3 |
d3 |
e3 |
f3 |
g3 |
a3 |
b3 |
c4 |
d4 |
e4 |
f4 |
g4 |
a4 |
A |
E |
I |
O |
U |
A |
E |
I |
O |
U |
A |
E |
I |
O |
U |
A |
Table 2.2: The rhythm values assigned by wordMusic
dependant of the number of consonants between each vowel.
<2 |
2-3 |
4 |
>4 |
Quaver |
Crotchet |
Minim |
Dotted Minim |
Technicalities
This interpretation of d'Arezzo's lookup chart is set up in a single
class, wordMusic.java.
However, a GUI interface which utilizes this class and allows new text
to be easily entered, has also been created and is called wordMusicMaker.java.
The default name of the generated MIDI file is "wordMusic.mid", although
this can be easily changed when using the GUI interface.
Observations
This melody generation tool, while based on a set of very simple rules,
is quite effective in creating musically interesting phrases.
Because the music it composes is generated entirely based on this set
of rules, it can be said to be taking an algorithmic approach to the generation
of music.
Initially, the simplicity of the rules used can be deceiving, however
when looked at more closely, they do have some theoretical grounding.
Most melodies that are written for specific texts do set notes to every
syllable, and the rhythm of the text does in general have some relationship
to the
length of the words (and the distance between adjacent vowels).
Although this is not an exact relationship (and problems occur with words
that do not contain vowels, for example "sky"), the results produced by
its
implementation are very acceptable. It should also be noted that the original
rhythm algorithm involved a greater variety of note lengths
(ranging from semiquavers to semibrieves), however this was simplified
as the resulting phrases tended to be somewhat disjointed.
Of course, the algorithm used could be extended further to take voice
leading into account, or could even be developed to produce polyphonic
phrases,
however, in its current form, the wordMusic melody generation tool does
provide a good example of the possibilities of algorithmically generating
music - even with only the simplest of rules.
The code: Let's
have a closer look.
import java.awt.*; import java.awt.event.*;
public class wordMusicMaker extends Frame implements ActionListener, WindowListener{
TextField fileName; TextArea wordInput; wordMusic musicMaker = new wordMusic();
public void actionPerformed(ActionEvent ae){ if(ae.getActionCommand() == "ActionCompose") { musicMaker.compose(wordInput.getText(), fileName.getText()); } } public void windowClosing(WindowEvent we) { System.exit(0); } public void windowActivated(WindowEvent we) {}; public void windowClosed(WindowEvent we) {}; public void windowDeactivated(WindowEvent we) {}; public void windowIconified(WindowEvent we) {}; public void windowDeiconified(WindowEvent we) {}; public void windowOpened(WindowEvent we) {}; public static void main(String args[]){ wordMusicMaker wmm = new wordMusicMaker("Word Music"); } public wordMusicMaker(String title){ super(title); this.addWindowListener(this); Image i = Toolkit.getDefaultToolkit().getImage("wmicon.gif"); this.setIconImage(i); setLayout(new BorderLayout()); Color lightGrey = new Color(240,240,240); this.setBackground(lightGrey); Label mainTitle = new Label("WORD MUSIC by Andrew Troedson", 1); add(mainTitle, "North");
wordInput = new TextArea("Type text here...", 6, 40, 3); wordInput.setBackground(Color.white); add(wordInput, "Center"); Panel windowBottom = new Panel(); Label outputFile = new Label("Output File:",1); fileName = new TextField("wordMusic.mid",16); Button compose = new Button("Compose"); compose.setBackground(Color.lightGray); compose.setForeground(Color.darkGray); compose.addActionListener(this); compose.setActionCommand("ActionCompose"); windowBottom.add(outputFile); windowBottom.add(fileName); windowBottom.add(compose); add(windowBottom, "South"); Panel eastBorder = new Panel(); add(eastBorder, "East"); Panel westBorder = new Panel(); add(westBorder, "West"); pack(); show(); } }
|
The code is adequately commented such that you should be able to follow
it thorugh.
It mainly implements a GUI which calls the wordMaker class whose code is
below.
import java.text.*; import jm.music.data.*; import jm.JMC; import jm.util.*;
public final class wordMusic implements JMC {
String passage;
String fileName;
public wordMusic() { } public void setPassage(String passage) { this.passage = passage; } public void setFileName(String fileName) { this.fileName = fileName; } / public void compose(String p, String f) { passage = p; fileName = f; Score score = new Score("wordMusic", 120); Part piano = new Part("Piano", PIANO, 0); Phrase phrase = new Phrase(0.0); Note nextNote = new Note(); if (passage.length() == 0) { setPassage("twinkle twinkle little star,"+ "how I wonder what you are,"+ " up above the world so high,"+ " like a diamond in the sky."); } if (fileName.length() == 0) { setFileName("wordMusic.mid"); } passage = passage.toUpperCase(); StringCharacterIterator iter = new StringCharacterIterator(passage);
int nonVowelCounter = 0; int notePitch; int randNum; for(int i=0; i<passage.length(); i++) { iter.setIndex(i); char nextChar = iter.current(); System.out.println(i + " " + nextChar); switch (nextChar) { case 'A': randNum = ((int)(java.lang.Math.random()*4)); if (randNum == 0){ notePitch = G2;} else if (randNum == 1){ notePitch = E3;} else if (randNum == 2){ notePitch = C4;} else { notePitch = a4;} nextNote = new Note(notePitch,setNoteLength( nonVowelCounter)); phrase.addNote(nextNote); nonVowelCounter = 0; break; case 'E': randNum = ((int)(java.lang.Math.random()*3)); if (randNum == 0){ notePitch = A2;} else if (randNum == 1){ notePitch = F3;} else { notePitch = D4;} nextNote = new Note(notePitch,setNoteLength( nonVowelCounter)); phrase.addNote(nextNote); nonVowelCounter = 0; break; case 'I': randNum = ((int)(java.lang.Math.random()*3)); if (randNum == 0){ notePitch = B2;} else if (randNum == 1){ notePitch = G3;} else { notePitch = E4;} nextNote = new Note(notePitch,setNoteLength( nonVowelCounter)); phrase.addNote(nextNote); nonVowelCounter = 0; break;
case 'O': randNum = ((int)(java.lang.Math.random()*3)); if (randNum == 0){ notePitch = C3;} else if (randNum == 1){ notePitch = A3;} else { notePitch = F4;} nextNote = new Note(notePitch,setNoteLength( nonVowelCounter)); phrase.addNote(nextNote); nonVowelCounter = 0; break;
case 'U': randNum = ((int)(java.lang.Math.random()*3)); if (randNum == 0){ notePitch = D3;} else if (randNum == 1){ notePitch = B3;} else { notePitch = G4;} nextNote = new Note(notePitch,setNoteLength( nonVowelCounter)); phrase.addNote(nextNote); nonVowelCounter = 0; break; default: nonVowelCounter++; break; } } piano.addPhrase(phrase); View.print(piano); score.addPart(piano);
Write.midi(score, fileName); }
static double setNoteLength(int counter){ double noteLength; switch (counter) { case (0): noteLength = Q; break; case (1): noteLength = Q; break; case (2): noteLength = C; break; case (3): noteLength = C; break; case (4): noteLength = M; break; default: //(ie more than 4 consonants) noteLength = MD; break; } return noteLength; } }
|
This is the class which does all the work.
The main thing to notice is the switch statement which checks to see if
the nexts letter is a vowel.
A switch statement is also used to select a duration based on the number
of letters between vowels. |