JFugue User's Guide
Get JFugue at http://www.jfugue.org.
See what's new in JFugue 2.0 in the appendix.Printing suggestion: If you want to print this guide, it is recommended that you print in Landscape mode. The wider pages will allow all of the values in the Appendix to fit on the page properly.
Table of Contents
- Welcome to JFugue
- Basics of JFugue
- Introducing the Music String
- Introducing Patterns
- Parsing and Rendering
- Working with MIDI
- Sample Programs
- Appendix
Welcome to JFugue
JFugue is a Java API for Music Programming. With JFugue, you can program music quickly and easily, and without knowing MIDI.
JFugue differs from other Java music API's in two significant ways. First, to program music in JFugue, you send strings that specify notes, instrument changes, controller messages, and other musical data. These strings are quick to create and easy to understand: for example, to play a C, you say
play("C");
. Other API's use objects to represent each note in a musical score, which makes music programming extremely tedious. Or, they require low-level manipulation of MIDI events.Second, JFugue lets you create "patterns" of music that can be manipulated, recombined, and transformed, allowing you to play and experiment with musical statements in new and interesting ways. Want to reverse your music, or change all of the notes by three intervals? All it takes it one method call.
JFugue is particular geared towards developers who need to create music during runtime. You can't play music that has already been recorded, because you don't know yet what the music is going to be! Applications include algorithmic or evolutionary music, music editors, and jazz improvisers.
You can use JFugue to play music while your application is running, or you can save music into MIDI files.
JFugue is 100% Java based. It uses the javax.sound.midi package to generate music.
Basics of JFugue
First, make sure you have the Java2 Standard Environment (J2SE) version 1.3 or later. You need at least version 1.3, because that's the version that has the javax.sound.midi packages.
You may want to see if additional MIDI sound banks are available for your Java installation. Installing additional sound banks may give you richer instrument sounds.
Next, you need the JFugue package, jfugue.jar, which you can download here. Remember where you put jfugue.jar; wherever it is, we'll call that directory %JFUGUE_DIR%.
Now you're ready to create your first music application! Let's walk through a quick program, so you can be sure you have everything set up correctly. Then we'll get into more details about programming JFugue.
Create a new file called MyMusicApp.java and enter this program:
import org.jfugue.*; public class MyMusicApp { public static void main(String[] args) { Player player = new Player(); Pattern pattern = new Pattern("C D E F G A B"); player.play(pattern); System.exit(0); } }Save the file and compile it, making sure jfugue.jar is in your classpath:
javac -classpath %JFUGUE_DIR%\jfugue.jar MyMusicApp.java
And run it...
java -classpath %JFUGUE_DIR%\jfugue.jar MyMusicApp
Turn up your speakers -- your first JFugue application should be singing to you! Wasn't that easy?
(You might be wondering why it's necessary to put
System.exit(0);
at the end of the program. It turns out that the Java MIDI classes open a bunch of threads, but they're not all closed properly when the song is done playing. This prevents the program from ending on its own, but it does not otherwise affect the execution of the program.)Introducing the Music String
The Music String is used to specify the notes, instrument changes, and other data required to play music. Along with Patterns, it is one of the two features of JFugue that make it unique, easy to use, and ideal for creating and experimenting with music.
The Music String is a string of characters, where each group of characters represents a musical command. It does not matter to the parser if you use upper or lowercase characters, but the following style guidelines are recommended to help keep your Music Strings readable:
- Use capital lettes for commands and notes
- Use lowercase characters for durations
- Used mixed-case for instrument and drum names
What commands are available?
Here is a list of the types of commands available in a Music String.
- Notes, Chords, and Rests: Specify a note or chord to play, and its duration. You may also indicate velocity for a note.
- Tempo: Specify the speed of the song.
- Voice: Indicate the voice (also known as the channel or track) in which notes are to be played.
- Instrument Change: Change the instrument, or patch, that is being used to play the notes.
- Controller Messages: Set any of the MIDI controller events, including portamento, balance, and much more.
- Variables: Define a value for use by the other commands.
Notes, Chords, and Rests
A note command begins with the note name or chord root, or the rest character:
A
,B
,C
,D
,E
,F
,G
, orR
; or, with a numeric representation of the note, which is explained below. The following paragraphs describe additional details you can specify for a note.Notes
You can indicate that a note is sharp or flat by using the
#
andb
characters, respectively.In addition to specifying a note using the note letter, there are two other ways to specify a note. One is to use the note value, which is a numerical value that indicates the note. MIDI has 128 notes, numbered 0 through 127. Note 60 is Middle-C. To specify a note value, enclose the value in square brackets; for example,
[60]
.The second way is to use a percussion name. In MIDI, the tenth voice (Voice 9, the voices begin with 0) is reserved for percussion sounds. There are a bunch of different percussion sounds you can play in that voice, and you can indicate them by giving the percussion name in brackets. For example,
[Hi_Bongo]
. Appendix: Percussion Sounds shows the names of the available percussion sounds.We'll talk about chords a bit later.
Octave
MIDI is capable of playing notes than span 10 octaves. This diagram shows the more common octaves.
![]()
To indicate an octave, use the numbers
0
through9
(remember, counting in MIDI starts at 0, so 0 through 9 is 10 octaves). For example, here's an A note in the 6th octave:A6
.If you don't specify the octave, the default is Octave 5, which includes Middle-C (so, Middle-C can be represented by both
C
andC5
).Duration
The Duration tells for how long to play the note. The following values are allowed. If you don't enter a duration, the default is a quarter note.
You can specify a dotted duration by following the duration character with a period ('.'). The duration of a dotted note is the original duration, plus half the duration.
w
- whole durationh
- half durationq
- quarter durationi
- eighth durations
- sixteenth durationt
- thirty-second durationx
- sixty-fourth durationn
- 1/128th durationYou can append durations to get a larger duration. For example,
qh.
would be a quarter note plus a dotted half note;wwww
is four whole notes.In addition to specifying a duration with a letter, you may also specify the duration as a decimal fraction. A quarter note would be 0.25, an eighth note would be 0.125, and so on. To represent a number as a decimal fraction, use the
/
character, followed by the fraction. For example, the following is an A note, 4th octave, half duration:A4/0.5
.Let's look at some examples. Here's a C5 half note:
C5h
. Can you think how to indicate a F-sharp, 4th octave, quarter note? The answer isF#4q
, orF#4/0.25
if you're using decimal fractions.Chords
Once you've specified the root of a chord, you can give its structure. All notes in a chord are played using the same instrument, in the same voice.
Here are the chord structures that are recognized by JFugue:
maj
- Majormin
- Minormaj7
- Major 7thmin7
- Minor 7thdim
- Diminishedaug
- Augmentedaug7
- Augmented 7thsus
- Sustainedadd9
- Add 9The chord indicator goes directly after the root, and before the octave or duration. For example, a C-major, 5th octave, quarter note would be
Special Note for Chords in the 7th Octave: If you want to play a major, minor, or augmented chord in the 7th octave, use note value instead of actual notes. For example, instead ofCmaj5q
. How would you specify a D-minor chord, 3rd octave, whole note? The answer isDmin3w
.Cmaj7
to indicate a C-major chord in the 7th octave, use[84]maj
. 84 is the note number for C7. You can understand how the parser would easily be confused betweenCmaj7
meaning "C-major chord in the 7th octave" and "C-major-7th chord". In fact, if you did sayCmaj7
, you would get a major seventh chord, with C5 as the root (using the default value for the octave). Incidentally,Cmaj75
would give you the same thing.Velocity
You can indicate how hard a note is struck, and how quickly the note is released.
To indicate how hard a note is struck, set the attack velocity using the
a
indicator, followed by a value from 0 to 127. To indicate how quickly a note is released, set the decay velocity using thed
indicator, followed by a value from 0 to 127.The default attack velocity and decay velocity for each note is 64. Incidentally, this is a standard default value for MIDI devices that do not support velocity.
Here's an example:
C5qa120d30
. This represents a Middle C, quarter duration, that is struck very strongly (120), and is released softly (30).Combining Notes
There are two special characters that you may use to combine notes. The plus (
+
) character can be used to play multiple notes in at the same time (in harmony). The underscore (_
) character can be used to play notes in order (in melody) when the melody is being played with a harmony. The scenarios below illustrate this.
Here are C, E, and G played in a melody. The music string to represent this piece of music is C5q E5q G5q
. Nothing new here.You can play more than one note at the same time using the same voice. To do this, connect notes with the plus ( +
) characer. For example,C5q+E5q+G5q
will play the C, E, and G notes, quarter duration, at the same time. In this particular case, you could also represent this harmony as a chord, since these notes make up a C-major chord:Cmaj5q
You can also play multiple notes at the same time with mixed durations. Use the underscore ( _
) character to indicate notes that should be played in sequence, while the sequence plays in parallel with other notes. For example, this set of notes would be played by the commandC5h+E5q_G5q
.Sample Note commands
Note commands are very useful, and as you write music for JFugue, you will find that they become easy to understand. Initially, they might seem a little intimidating. Here are some examples, which descriptions that may help you understand them better.
A
- Play an A note, fifth octave (default), quarter duration (default).Rw
- A whole-duration rest.Cmaj3w
- Play a C-major chord, octave 3, whole duration.[77]h
- Play note #77 (equal to a F, 6th octave - remember note #60 is Middle-C), half duration.[Cowbell]qi
- This note is intended for Voice 9, the percussion channel. It plays a cowbell sound for a quarter plus eighth duration. If you played this note in a voice other than Voice 9, you'd get Note #56, since the code for a cowbell is 56 (see the list of percussion sounds for more info). That would be A#, 4th octave.D4q+F4q+A4q
- Plays the notes D, F, and A together; this would play the same notes asDmin4q
.C5w+E5h_G5h+Dmaj3w
- Plays a C note, fifth octave, whole duration; at the same time, plays an E, fifth octave, half duration, followed by a G, fifth octave, half duration; at the same time, plays a D-major chord, third octave, whole duration. Be aware that a better way to play this might be to play the notes in one voice and the chord in another voice; for example,V0 C5W+E5h_G5h V1 Dmaj3w
orV0 C5w V1 E5h G5h V2 Dmaj3w
.Tempo
You should specify the tempo of your song - how fast or slow the song should be played. The tempo value represents "Pulses Per Quarter", or PPQ, which is how many "pulses", or clock cycles, to give a quarter note. A smaller value will result in a faster song, and a larger number will result in a slower song. A good value to start with is 120; this is also the default if you do not specfy a tempo.
You only have to specify the tempo once in your music string, even if you are using multiple voices. Different voices cannot have different tempos. Also, it does not matter where you specify the tempo in your Music String, although it is recommended that you place it at the very beginning of a song.
The command is a T, followed by a number from 0 to infinity. For example:
T120
.Voice
The Voice command tells JFugue to play the following notes in the given MIDI voice (also known as a channel). You can think of a voice as a musical track. Voices give you the ability to play multiple melodies at the same time. If you're programming piano music, you can use one voice for the treble clef, and a second voice for the bass clef. If you're creating a symphonic piece, you could give each instrument its own track.
The command is a V, followed by a number from 0 to 15. For example:
V5
There are 16 voices, numbered 0 through 15. The tenth voice (or channel) is special -- it is the channel that plays the rhythym instruments. Notes played in this voice sound like drums, cymbals, woodblocks, and other percussion instruments. Since we're counting from 0, the tenth voice is Voice 9. When playing notes on Voice 9, you can use percussion names to represent the percussion instruments; see the Note command for details on this.
Instrument Change
The Instrument Change command tells JFugue to play the following notes with the given MIDI instrument number or name.
The command is an I, followed by either a number from 0 to 127, or the name of an instrument enclosed in brackets:
I9 I[Guitar]Instrument changes (also known as patch changes) are specific to the voice in which the change takes place. In the following example, the notes A and B will be played with the Piano, and C and D with the Flute:
V0 I[Piano] A V1 I[Flute] C V0 B V1 D
Appendix: Instrument Names contains pre-set names for instruments. You may also create your own names for instruments using the Variable command.
Controller Messages
The MIDI specification defines about 100 controller events, which are used to specify a wide variety of settings that control the sound of the music. These include foot pedals, left-to-right balance, portamento (notes sliding into each other), tremulo, and lots more. For a complete list, refer to a MIDI specification document.
The Controller command,
X
, tells JFugue to set the given controller:
Xcontroller_number=value X37=18 X[Chorus_Level]=64If you're familiar with MIDI Controllers, you know that there 14 controllers that have both "coarse" and "fine" settings. These controllers essentially have 16 bits of data, instead of the typical 8 bits (one byte) for most of the others. There are two ways that you can specify coarse and fine settings.
The first way is quite uninspired:
X[Foot_Pedal_Coarse]=10 X[Foot_Pedal_Fine]=65Surely, JFugue can be smarter than this. Indeed it is: For any of those 14 controller events that have coarse and fine components, you can specify both values at the same time:
X[Foot_Pedal]=1345There you have it. Want to set the volume to 10200, out of a possible 16383? There's no need to figure out what the high byte and low byte of 10200 are. Just use
X[Volume]=10200
.The numeric value of the word VOLUME is equal to a 16-bit number, using the value for VOLUME_COARSE as the high byte, and the value for VOLUME_FINE as the low byte.
Some controller events have two settings: ON and OFF. Normally, ON means 127 and OFF means 0. JFugue has defined two constants, ON and OFF, that you can use instead of the numbers:
X[Local_Keyboard]=ON
. JFugue has also defined DEFAULT, which is set to 64.Defining Constants
When you're programming music, your main task is to make beautiful sounds - not to be inundated with random and meaningless numbers. You should be able to set the VOLUME and use the FLUTE, without having to remember that VOLUME is 935 and FLUTE is 73.
The command to set a constant is as follows:
$WORD=DEFINITIONHere's an example:
$ELEC_GRAND=2
. Of course, JFugue has already defined ELECTRIC_GRAND to be 2. But maybe you'd like to use a shorter name, or maybe you have a more memorable name for this instrument, like simply ELEC.JFugue defines a bunch of constants - around 360! - for things like instrument names, percussion instruments, and controller events. Creating these defintions is the job of the JFugueDefinitions class.
Words that are defined with the Constants command are put into the JFugue Dictionary, ready to be looked up whenever you refer to them.
Constants are also useful in cases where you have settings that you may want to change some day. Suppose you want to play some music with your favorite instrument, the piano. You could definine FAV_INST to be 0, and then you can say
I[Fav_Inst]
when you want to use it. But if your favorite instrument ever changes, all you have to change in your music string is the definition of FAV_INST; you do not have to change every place where you refer to your favorite instrument.You can use a constant anyplace where a number would be expected, with the exception of the Octave value (but that's okay, because you can just specify the note itself, with the octave, as a single number), and if you're using a constant for a duration, you have to use decimal duration values (and preceed the duration with a slash,
/
).You should place the constant word in square brackets, but depending on the circumstance, the parser will probably still understand the word if you don't use the brackets.
Introducing Patterns
A pattern is a collection of notes that comprise a musical statement. A pattern can represent an entire song, individual parts of a song, or snippets of frequently used music. Patterns may be created from other patterns, and the music in a pattern may be transformed in interesting and creative ways.
Patterns as parts of a song
Patterns may be used to represent parts of a song. Suppose you're writing a standard rock or pop song. You might break your song into the following parts:
Many of these parts share similarities. For example, the chorus will probably be the same throughout the song. The verses will have the same music, even if the words are different. The outro is probably a repetition of the chorus as it fades away.
- Intro
- Verse 1
- Chorus
- Verse 2
- Chorus
- Breakdown / Interlude
- Verse 3
- Chorus
- Outro
To program this in JFugue, you can create the sections of music as patterns:
Then, you can create the song using those sections. We'll even create a verseAndChorus pattern, since that is repeated three times:
Pattern intro = new Pattern("music string"); Pattern verse = new Pattern("music string"); Pattern chorus = new Pattern("music string"); Pattern breakdown = new Pattern("music string"); Pattern outro = new Pattern("music string");
Pattern verseAndChorus = new Pattern(); verseAndChorus.add(verse); verseAndChorus.add(chorus); Pattern song = new Pattern(); song.add(intro); song.add(verseAndChorus,2); // This adds verseAndChorus twice song.add(breakdown); song.add(verseAndChorus); song.add(outro);You can play the entire song by saying
player.play(song);
. You may also play the individual sections outside of the song itself:player.play(breakdown);
.Pattern Factories
If you're creating a song that needs a drum track, wouldn't it be cool if you could just make a method call that would instantly give you a Rock rhythm, or an 8-Beat rhythm, or even a Swing rhythm? With JFugue, you can!
A pattern factory gives you a pattern that you can use in your own songs. You can also write your own pattern factories - and if you create your own and place them on the Web, let me know so I can link to you so others around the world can use your rhythms.
A pattern factory call looks like this:
That's it!RockPatternFactory rpf = new RockPatternFactory(); Pattern rhythm = rpf.getPattern(0);
RockPatternFactory is supplied with JFugue, and can be found in the org.jfugue.demo package.
Some factories also provide different parts of the same rhythm. For example, RockPatternFactory has a fill-in pattern that can be accessed with
getPattern(2);
. You could hear all of the different patterns a PatternFactory can produce by calling the pattern factory's getDemo method:The demo will play all of the different patterns that the factory can produce, added together in one pattern that is returned fromPlayer player = new Player(); RockPatternFactory rpf = new RockPatternFactory(); Pattern demo = rpf.getDemo(); player.play(demo);
getDemo()
.Information on writing your own pattern factory is provided below.
Pattern Transformers
One of the coolest things about patterns of music is that you can apply a transformation on them, and get different music based on the same musical base.
What are some things you might want to do to transform a pattern? There are many; here are a few ideas:
The list of potential transformations is limitless, which is why you're able to create your own pattern transformers.
- Sort the notes in order of highest to lowest, or otherwise re-arrange their order
- Increase the interval between notes
- Add an echo to the notes
- Perform notes in a pattern with tremolo
The JFugue package comes with a few pattern transformers. They're all named XxxxPatternTransformer, where Xxxx indicated what they do - for example, IntervalPatternTransformer changes the intervals between notes, DurationPatternTransformer changes the duration of notes, and ReversePatternTransformer reverses a pattern.
Before using a pattern transformer, you have to know what variables they expect. For example, the IntervalPatternTransformer needs to know by how many steps to change the intervals between notes. This information can be found in the comments of the pattern transformer code, or in documentation that accompanies the transformer. There is also a method, getVariables(), that you can call on a transformer. If you print that output, you'll see what is required:
If you're writing a music editing program and you want to use pattern transformers, you can use the getVariables() method to get a list of the variables required, which you may then present in your user interface. The output from getVariables() should be easy to parse.IntervalPatternTransformer ipt = new IntervalPatternTransformer(); String output = ipt.getVariables(); System.out.println(output);
To set a pattern transformer variable, use the setVariable() method. This method takes two arguments. The first is a String representing the name of the variable. You can type the actual string, but to keep with programming best practices, it's best to use the constants provided by the class to represent the string. For example, IntervalPatternTransformer defines a static constant, INTERVAL, which contains the string "Interval". If you mis-type the word INTERVAL when referring to the constant, you'll get a compile-time error that you can fix immediately. But if you happen to mistype the string "Interval", the program will compile cleanly, although it won't work as you expect.
Player player = new Player(); Pattern pattern = new Pattern("music string"); IntervalPatternTransformer ipt = new IntervalPatternTransformer(); ipt.setVariable(IntervalPatternTransformer.INTERVAL, 2); Pattern transformedPattern = ipt.transform(pattern); player.play(transformedPattern);
Information on writing your own pattern transformer is provided below.
Pattern Tools
Patterns are a great way to manage sections of a musical statement. As you're using patterns, you may realize the need to perform some calculation on a pattern. How long does this pattern play? What is the last voice that was used in this pattern? How many A notes are there in this pattern?
Pattern tools are used to perform calculations across a pattern. Like pattern transformers, they are parser listeners, and they work by parsing the pattern, and performing their calcuations when the parser makes callbacks to the event methods (for example,
voiceEvent(Voice voice)
).There is one pattern tools that ships with JFugue. DurationPatternTool lets you know how long a pattern plays. You can use DurationPatternTool as an example for your own tools.
To use a pattern tool, first instantiate the tool, then call its
execute
method. Theexecute
method takes a pattern as its parameter, and returns an object with the result. You can also get the result of a pattern tool calculation that has already been performed by callinggetResult()
. Here's an example:
Pattern pattern = new Pattern("music string"); DurationPatternTool dpt = new DurationPatternTool(); System.out.println("Duration of pattern is " + dpt.execute(pattern));
Information on writing your own pattern transformer is provided below.
Writing Your Own Pattern Factory
Writing your own Pattern Factory is easy. Simply create a new class that extends
PatternFactory
, and fill in thegetPattern(int whichPattern)
andgetDemo()
methods.
getPattern(int)
should return a pattern, and you can return different patterns based on the value passed in. If you're creating an 8-Beat rhythm, for example, you might want to make a 0 return the base rhythm, a 1 return a slightly different base rhythm, a 2 return a breakdown, a 3 return an intro, and a 4 return an outro. Your code might look like this:public Pattern getPattern(int whichPattern) { Pattern pattern = new Pattern(); switch(whichPattern) { default, case 0 : pattern.setMusicString("notes for base rhythm"); break; case 1 : pattern.setMusicString("notes for alternate base rhythm"); break; case 2 : pattern.setMusicString("notes for breakdown"); break; case 3 : pattern.setMusicString("notes for intro"); break; case 4 : pattern.setMusicString("notes for outro"); break; } return pattern; }
You also have to flesh out the
getNumberOfPatterns()
method. This method returns an integer that indicates how many patterns your factory can produce. Remember to start counting at 0 -- so if your Pattern Factory produces 5 patterns, they should be numbered 0 through 4 in your getPattern() method.The PatternFactory class automatically creates a demo for your Factory. This is composed of a number of beeps that indicate which pattern will be played (pattern 0 gets no beeps), followed by the pattern. The demo uses getNumberOfPatterns() to determine how many patterns the factory can produce. Use the
getDemo()
method to get a PatternFactory's demo.Writing Your Own Pattern Transformer
A PatternTransformer can do some powerful things with your patterns. The ability to modify musical patterns is a unique feature that only JFugue delivers.
To begin, create a new class that extends
PatternTransformer
. PatternTransformer implements ParserListener. When the Parser object translates musical patterns from strings to data that is more easily understood by the computer, it sends events to ParserListeners.Your Pattern Transformer will also listen for parsed events. Your transformer can then do interesting things with these events.
The first thing to do is to override the ParserListener methods. There are seven of them, but you don't have to override all of them. Each is implemented in PatternTransformer itself; in there, the method simply adds the event to the return pattern. If you extend PatternTransformer but do not override any of the event methods, you will get a pattern transformer that simply returns the same pattern that went in. These are the seven event methods:
public void voiceEvent(Voice voice) public void tempoEvent(Tempo tempo) public void instrumentEvent(Instrument instrument) public void controllerEvent(Controller controller) public void noteEvent(Note note) public void sequentialNoteEvent(Note note) public void parallelNoteEvent(Note note)
If you're creating a Transformer that will modify note values, make sure that all three note methods perform the transformation. For more information on parser listening, see this section.
Add all of your changes to the
returnPattern
variable.returnPattern
is defined by PatternTransformer.java, and it is the pattern that holds the transformed pattern.Here is an example of a transformer that will always convert all flute instrument changes into saxophones:
public void instrumentEvent(Instrument instrument) { // The Flute is Instrument 73 // The Soprano_Sax is Instrument 64 if (instrument.getInstrumentNumber() == 73) { instrument.setInstrumentNumber(64); } returnPattern.addElement(instrument); }
When you're dealing with Note event, you will always handle both the note itself and its duration as values, not as letters. So, even though you may say
C5q
to play an C-note, 5th octave, quarter duration, in your noteEvent methods, you'll be dealing with[60]/0.25
. This makes it very easy to modify note values and durations, since all you have to do is a little math - you don't have to interpret letters.Here's an example, straight from DurationPatternTransformer. It changes the duration of notes based on a factor passed in as a variable. For brevity, only the important event callback methods are shown.
public void noteEvent(Note note) { double durationValue = note.getTotalDurationNumber(); durationValue *= ((Double)getVariable(FACTOR)).doubleValue(); note.setTotalDurationNumber(durationValue); returnPattern.addElement(note); } public void sequentialNoteEvent(Note note) { // same stuff as in noteEvent } public void parallelNoteEvent(Note note) { // same stuff as in noteEvent }
In addition to the event callback methods, you have to override
getDescription()
, which should return a String giving a quick description of what this transformer does.Next, you have to indicate to the user what variables are required by the transformer. For example, the IntervalPatternTransformer requires that the user tell the transformer by how many intervals to transform a pattern.
To do this, extend the
getVariables()
method, and return a String that contains the needed information.There is a format to the
getVariables()
string that must be followed for consistency. Notice the use of quotes and slashes.If you need to return multiple Strings, end each String with a'variable name'/type/description/default
\n
, the newline character.Also, be sure to add your strings to the JavaDoc for the getVariables() method as well, so users can learn what your code needs from its documentation.
Here's an example, straight from IntervalPatternTransformer:
/** * Returns a string declaring what variables IntervalPatternTransformer * can use to perform the transformation. * <p> * IntervalPatternTransformer requires the following:<br> * <i>'interval'</i> - Integer - Number of intervals by * which to change each note, can be positive or negative. * Default is 1. * </p> */ public String getVariables() { String returnString = "'interval'/int/Number of intervals "+ "by which to change each note, can "+ "be positive or negative/1"; return returnString; }
Finally, one last thing to do is to create a constructor for your class that defines the default values for your variables. This is important because otherwise, people (including yourself!) who are using your transformer and forget to set the variables will find that their program crashes at runtime.
When you're declaring your own constructor, make sure to call the parent constructor first by using
super()
. Here's an example from IntervalPatternTransformer:public IntervalPatternTransformer() { super(); putVariable(INTERVAL,new Integer(1)); }
You're done! When someone wants to use your Transformer, they will have to set the variables that you declared to be important, and then they can call
YourPatternTransformer.transform(pattern)
to get their transformed pattern!A quick review of the steps:
- 1. Override any of the seven event callback methods
- 2. Create a getDescription method that returns a string
- 3. Create a getVariables method that returns a string that follows the standard format metioned above
- 4. Make sure your constructor initializes the variables used by the transformer
Writing Your Own Pattern Tool
It's pretty easy to make your own Tool to perform a calculation on a given pattern. Like the Pattern Transformer, a Pattern Tool is a ParserListener, so you may override any of the following methods:
public void voiceEvent(Voice voice) public void tempoEvent(Tempo tempo) public void instrumentEvent(Instrument instrument) public void controllerEvent(Controller controller) public void noteEvent(Note note) public void sequentialNoteEvent(Note note) public void parallelNoteEvent(Note note)
In addition, like the Pattern Transformer, you have to override
getDescription()
, which should return a String giving a quick description of what this tool does.You must create a
reset()
method. This method simply sets the counters and variables in your tool to their initial states. It is called whenever the tool is executed. By requiringreset()
, users can create a PatternTool object once, then re-use it on multiple patterns:
Pattern pattern1 = new Pattern("music string 1"); Pattern pattern2 = new Pattern("music string 2"); DurationPatternTool dpt = new DurationPatternTool(); System.out.println("Duration of pattern 1 is " + dpt.execute(pattern1)); // If execute() didn't call reset(), then the next line might give a bad // result, because its variables still have calculations from the first // time it was used System.out.println("Duration of pattern 2 is " + dpt.execute(pattern2));
Finally, you must create a
getResult()
method. This method returns the answer that the Pattern Tool is meant to calculate. It is called at the end ofexecute()
, and it may also be called as often as you wish to get the result from the calculation, without actually perfoming the entire calculation again:
Pattern pattern = new Pattern("music string"); DurationPatternTool dpt = new DurationPatternTool(); System.out.println("Duration of pattern is " + dpt.execute(pattern)); System.out.println("That value again is " + dpt.getResult()); System.out.println("One more time, without running the calculation: " + dpt.getResult());
Parsing and Rendering
When you send a music string to JFugue, the tokens in the string are parsed, or intepreted. These interpreted tokens then go to the renderer, which turns events into MIDI musical events.
Listening to the Parser
When a token is parsed, the parser sends callback events to all parser listeners. You can listen to these events to find out what the parser is interpreting. To listen to events from the parser, your class needs to implement ParserListener and add itself to the parser's list of parser listeners with the
addActionListener
method.The Renderer is one example of a parser listener. As each token is parsed, the Renderer gets an event, which it uses to add MIDI evnts to the music sequence.
There are seven callback methods:
public void voiceEvent(Voice voice) public void tempoEvent(Tempo tempo) public void instrumentEvent(Instrument instrument) public void controllerEvent(Controller controller) public void noteEvent(Note note) public void sequentialNoteEvent(Note note) public void parallelNoteEvent(Note note)
Notice that there are three different methods for notes: noteEvent, sequentialNoteEvent, and parallelNoteEvent. The method
noteEvent
is fired when a single note comes through, such asA5q
. The methodsequentialNoteEvent
is fired when the underscore character is used to connect notes, as inA5q_C4q
. The methodparallelNoteEvent
is fired when the plus character is used to connect notes, or when a chord is played, as inA5q+C5q
orCminq
.Idea: a Sheet Music Renderer
The Renderer class takes parser events and turns them into music. Similarly, you could create a SheetmusicRenderer class that would take parser events and turn them into graphics.
Adding new tokens to the Music String
If you find the need to add new tokens to the music string, here's what to do.
In Parser.java, find the bit
switch
statement, and add an entry for your new token. Make sure your token begins with a character that isn't already used.Create a new method that will actually do the parsing. You can model this method after something like
parseInstrumentElement
.The ultimate result of your parsing method should call a new event callback that you will add to ParserListener.java. For completeness, you should also update ParserListenerAdapter.java and PatternTransformer.java, which both implement ParserListener.
If you'd like to watch the parser as it goes about parsing, turn on tracing:
Parser.setTracing(Parser.TRACING_ON);
. You can also print new tracing output with thetrace
method.Working with MIDI
When you play a pattern of music through JFugue, everything you specified in the Music String is parsed and turned into MIDI events. It is these MIDI events that you hear when you play a song.
Saving your music in MIDI files
You can save the output of your program as a MIDI file. All of the MIDI files available on these pages were created with JFugue programs, the outputs of which were saved to MIDI.
Saving your song as a MIDI file is very easy to do:
player.save("filename");
. You have to throw a try/catch block around the save method, just in case there's a problem writing the file. Here's a more complete example:Player player = new Player(); Pattern pattern = new Pattern("music string"); try { player.save(pattern,"filename"); } catch (Exception e) { e.printStackTrace(); }
You cannot load MIDI data into a Player, because the Player always generates a fresh new sequence based on the Patterns that it is asked to play.
Getting the MIDI sequence
If you ever feel the need to get the MIDI sequence after JFugue has rendered it, you can do it using
player.getSequencer();
. The Player does not have a setSequencer() method because it always creates a new Sequencer object to play music specified by Patterns.Sample Programs
One of the best ways to learn something new is to see it in action. The following samples are complete programs that show how to use JFugue.
Example 1: A Simple Song
In this simple song, you'll be introduced to the Music String, which is how music data is represented in JFugue. The Pattern is split across multiple lines so it's easier to read.
import com.innix.jfugue.Player; import com.innix.jfugue.Pattern; public class Example1 { public static void main(String[] args) { Player player = new Player(); Pattern pattern = new Pattern("T160 I[Cello] "+ "G3q G3q G3q Eb3q Bb3i G3q Eb3q Bb3i G3h"); player.play(song); } }Example 2: "Frere Jacques"
In this example, we'll use patterns to easily replicate identical pieces of music. In the sheet music below, you'll notice that there are eight measures, but measures 1 and 2 are duplicates of each other, as are measures 3 and 4, 5 and 6, and 7 and 8. Instead of re-typing the duplicate measures, we can just add that pattern to the song twice.
![]()
import com.innix.jfugue.Player; import com.innix.jfugue.Pattern; public class FrereJacques { public static void main(String[] args) { Player player = new Player(); // "Frere Jacques" Pattern pattern1 = new Pattern("C5q D5q E5q C5q"); // "Dormez-vous?" Pattern pattern2 = new Pattern("E5q F5q G5h"); // "Sonnez les matines" Pattern pattern3 = new Pattern("G5i A5i G5i F5i E5q C5q"); // "Ding ding dong" Pattern pattern4 = new Pattern("C5q G4q C5h"); // Put it all together Pattern song = new Pattern(); song.add(pattern1); song.add(pattern1); song.add(pattern2); song.add(pattern2); song.add(pattern3); song.add(pattern3); song.add(pattern4); song.add(pattern4); // Play the song! player.play(song); } }Example 3: "Frere Jacques" as a round
The previous example showed how to use patterns to replicate similar pieces of music. In this example, we'll turn the whole song into a pattern, so we can replicate the entire song. With this technique, we can create a round.
Notice how in this example, we're adding sections of songs together in a single pattern, as we did in Example 2. In Example 2 the patterns are played in order, but in Example 3 the patterns will be played at the same time. To do this, we add each pattern in a different voice with the
V0
,V1
, andV2
Music String commands. All voices are played simultaneously. TheRw Rw
Music String represents two whole-note rests, which are used to stagger the simultaneous patterns so they each start two measures apart.This example requires the code from Example 2. Replace the "Play the song!" and "player.play(song)" lines in Example 2 with the following program segment.
Click here to listen to the song this program generates: FrereJacques.mid
Pattern doubleMeasureRest = new Pattern("Rw Rw"); // Create the first voice Pattern round1 = new Pattern("V0 "); round1.add(song); // Create the second voice Pattern round2 = new Pattern("V1 "); round2.add(doubleMeasureRest); round2.add(song); // Create the third voice Pattern round3 = new Pattern("V2 "); round3.add(doubleMeasureRest); round3.add(doubleMeasureRest); round3.add(song); // Put the voices together Pattern roundSong = new Pattern(); roundSong.add(round1); roundSong.add(round2); roundSong.add(round3); // Play the song! player.play(roundSong);Appendix
What's New in JFugue 2.0
JFugue 1.0 introduced the world to JFugue, and gave music programmers an easy way to create music using music strings and patterns, and saving files as MIDI.
JFugue 2.0 improves on the first version, and it introduces the following new features:
- Support for MIDI Controller Events in the Music String
- Attack and decay velocity for notes, to indicate how sharply a note is struck, or how quickly is it released
- User-definable constants (dictionary entries), for referring to instruments, voices, and other values in your Music String by names that are specifically memorable to you
- Introduction of Pattern Tools for performing calculations on a pattern
- JFugue package is now org.jfugue, not com.innix.jfugue
- Internal modifications to the Parser, which makes modifying the parser more clear
- More complete JavaDoc comments
Upgrading to JFugue 2.0
If you have used JFugue 1.0 and you want to use JFugue 2.0, you should know the following things:
- The package name has changed. To include the JFugue files, you need to say
import org.jfugue.*;
instead ofimport com.innix.jfugue.*;
- Bookmark events, which were never fully implemented, have been removed. Controller events have been added. If you have created any ParserListener or PatternTransformer classes, remove the
bookmarkEvent(Bookmark bookmark)
method, and add thecontrollerEvent(Controller controller)
method.Instrument names
The following words come pre-defined in the JFugue parser. You can use any of these values to specify an instrument. For example, to play music using the clavinet, you can say
I[Clavinet]
PIANO 0 ACOUSTIC_GRAND 0 BRIGHT_ACOUSTIC 1 ELECTRIC_GRAND 2 HONKEY_TONK 3 ELECTRIC_PIANO 4 ELECTRIC_PIANO_1 4 ELECTRIC_PIANO_2 5 HARPISCHORD 6 CLAVINET 7 CELESTA 8 GLOCKENSPIEL 9 MUSIC_BOX 10 VIBRAPHONE 11 MARIMBA 12 XYLOPHONE 13 TUBULAR_BELLS 14 DULCIMER 15 DRAWBAR_ORGAN 16 PERCUSSIVE_ORGAN 17 ROCK_ORGAN 18 CHURCH_ORGAN 19 REED_ORGAN 20 ACCORIDAN 21 HARMONICA 22 TANGO_ACCORDIAN 23 GUITAR 24 NYLON_STRING_GUITAR 24 STEEL_STRING_GUITAR 25 ELECTRIC_JAZZ_GUITAR 26 ELECTRIC_CLEAN_GUITAR 27 ELECTRIC_MUTED_GUITAR 28 OVERDRIVEN_GUITAR 29 DISTORTION_GUITAR 30 GUITAR_HARMONICS 31 ACOUSTIC_BASS 32 ELECTRIC_BASS_FINGER 33 ELECTRIC_BASS_PICK 34 FRETLESS_BASS 35 SLAP_BASS_1 36 SLAP_BASS_2 37 SYNTH_BASS_1 38 SYNTH_BASS_2 39 VIOLIN 40 VIOLA 41 CELLO 42 CONTRABASS 43 TREMOLO_STRINGS 44 PIZZICATO_STRINGS 45 ORCHESTRAL_STRINGS 46 TIMPANI 47 STRING_ENSEMBLE_1 48 STRING_ENSEMBLE_2 49 SYNTHSTRINGS_1 50 SYNTHSTRINGS_2 51 CHOIR_AAHS 52 VOICE_OOHS 53 SYNTH_VOICE 54 ORCHESTRA_HIT 55 TRUMPET 56 TROMBONE 57 TUBA 58 MUTED_TRUMPET 59 FRENCH_HORN 60 BRASS_SECTION 61 SYNTHBRASS_1 62 SYNTHBRASS_2 63 SOPRANO_SAX 64 ALTO_SAX 65 TENOR_SAX 66 BARITONE_SAX 67 OBOE 68 ENGLISH_HORN 69 BASSOON 70 CLARINET 71 PICCOLO 72 FLUTE 73 RECORDER 74 PAN_FLUTE 75 BLOWN_BOTTLE 76 SKAKUHACHI 77 WHISTLE 78 OCARINA 79 LEAD_SQUARE 80 SQUARE 80 LEAD_SAWTOOTH 81 SAWTOOTH 81 LEAD_CALLIOPE 82 CALLIOPE 82 LEAD_CHIFF 83 CHIFF 83 LEAD_CHARANG 84 CHARANG 84 LEAD_VOICE 85 VOICE 85 LEAD_FIFTHS 86 FIFTHS 86 LEAD_BASSLEAD 87 BASSLEAD 87 PAD_NEW_AGE 88 NEW_AGE 88 PAD_WARM 89 WARM 89 PAD_POLYSYNTH 90 POLYSYNTH 90 PAD_CHOIR 91 CHOIR 91 PAD_BOWED 92 BOWED 92 PAD_METALLIC 93 METALLIC 93 PAD_HALO 94 HALO 94 PAD_SWEEP 95 SWEEP 95 FX_RAIN 96 RAIN 96 FX_SOUNDTRACK 97 SOUNDTRACK 97 FX_CRYSTAL 98 CRYSTAL 98 FX_ATMOSPHERE 99 ATMOSPHERE 99 FX_BRIGHTNESS 100 BRIGHTNESS 100 FX_GOBLINS 101 GOBLINS 101 FX_ECHOES 102 ECHOES 102 FX_SCI-FI 103 SCI-FI 103 SITAR 104 BANJO 105 SHAMISEN 106 KOTO 107 KALIMBA 108 BAGPIPE 109 FIDDLE 110 SHANAI 111 TINKLE_BELL 112 AGOGO 113 STEEL_DRUMS 114 WOODBLOCK 115 TAIKO_DRUM 116 MELODIC_TOM 117 SYNTH_DRUM 118 REVERSE_CYMBAL 119 GUITAR_FRET_NOISE 120 BREATH_NOISE 121 SEASHORE 122 BIRD_TWEET 123 TELEPHONE_RING 124 HELICOPTER 125 APPLAUSE 126 GUNSHOT 127Percussion names
Voice 9 is a special channel that plays percussion sounds instead of musical notes. You can use these percussion sound names in place of a note value when playing music on Voice 9. For example:
V9 [Bass_Drum]q
would play a bass drum for a quarter duration.You can play more than one percussion sound at the same time by adding them together, just like you were playing multiple notes at the same time. This example will play a hand clap and a cymbal crash at the same time:
V9 [Hand_Clap]q+[Crash_Cymbal_1]q
ACOUSTIC_BASS_DRUM 35 BASS_DRUM 36 SIDE_STICK 37 ACOUSTIC_SNARE 38 HAND_CLAP 39 ELECTRIC_SNARE 40 LOW_FLOOR_TOM 41 CLOSED_HI_HAT 42 HIGH_FLOOR_TOM 43 PEDAL_HI_HAT 44 LOW_TOM 45 OPEN_HI_HAT 46 LOW_MID_TOM 47 HI_MID_TOM 48 CRASH_CYMBAL_1 49 HIGH_TOM 50 RIDE_CYMBAL_1 51 CHINESE_CYMBAL 52 RIDE_BELL 53 TAMBOURINE 54 SPLASH_CYMBAL 55 COWBELL 56 CRASH_CYMBAL_2 57 VIBRASLAP 58 RIDE_CYMBAL_2 59 HI_BONGO 60 LOW_BONGO 61 MUTE_HI_CONGA 62 OPEN_HI_CONGA 63 LOW_CONGA 64 HIGH_TIMBALE 65 LOW_TIMBALE 66 HIGH_AGOGO 67 LOW_AGOGO 68 CABASA 69 MARACAS 70 SHORT_WHISTLE 71 LONG_WHISTLE 72 SHORT_GUIRO 73 LONG_GUIRO 74 CLAVES 75 HI_WOOD_BLOCK 76 LOW_WOOD_BLOCK 77 MUTE_CUICA 78 OPEN_CUICA 79 MUTE_TRIANGLE 80 OPEN_TRIANGLE 81Controller names
The MIDI specification defines a number of controllers that modify how music sounds. You can use any of these controller names with the Controller command. For example, to set the hold pedal, you can say
X[Hold_Pedal]=127
.Some of these controller events come in coarse/fine pairs. You can set these controllers separately, or together using the combined controller names.
BANK_SELECT_COARSE 0 MOD_WHEEL_COARSE 1 BREATH_COARSE 2 FOOT_PEDAL_COARSE 4 PORTAMENTO_TIME_COARSE 5 DATA_ENTRY_COARSE 6 VOLUME_COARSE 7 BALANCE_COARSE 8 PAN_POSITION_COARSE 10 EXPRESSION 11 EFFECT_CONTROL_1_COARSE 12 EFFECT_CONTROL_2_COARSE 13 SLIDER_1 16 SLIDER_2 17 SLIDER_3 18 SLIDER_4 19 BANK_SELECT_FINE 32 MOD_WHEEL_FINE 33 BREATH_FINE 34 FOOT_PEDAL_FINE 36 PORTAMENTO_TIME_FINE 37 DATA_ENTRY_FINE 38 VOLUME_FINE 39 BALANCE_FINE 40 PAN_POSITION_FINE 42 EXPRESSION 43 EFFECT_CONTROL_1_FINE 44 EFFECT_CONTROL_2_FINE 45 HOLD_PEDAL 64 HOLD 64 PORTAMENTO 65 SUSTENUTO_PEDAL 66 SUSTENUTO 66 SOFT_PEDAL 67 SOFT 67 LEGATO_PEDAL 68 LEGATO 68 HOLD_2_PEDAL 69 HOLD_2 69 SOUND_VARIATION 70 VARIATION 70 SOUND_TIMBRE 71 TIMBRE 71 SOUND_RELEASE_TIME 72 RELEASE_TIME 72 SOUND_ATTACK_TIME 73 ATTACK_TIME 73 SOUND_BRIGHTNESS 74 BRIGHTNESS 74 SOUND_CONTROL_6 75 CONTROL_6 75 SOUND_CONTROL_7 76 CONTROL_7 76 SOUND_CONTROL_8 77 CONTROL_8 77 SOUND_CONTROL_9 78 CONTROL_9 78 SOUND_CONTROL_10 79 CONTROL_10 79 GENERAL_PURPOSE_BUTTON_1 80 GENERAL_BUTTON_1 80 BUTTON_1 80 GENERAL_PURPOSE_BUTTON_2 81 GENERAL_BUTTON_2 81 BUTTON_2 81 GENERAL_PURPOSE_BUTTON_3 82 GENERAL_BUTTON_3 82 BUTTON_3 82 GENERAL_PURPOSE_BUTTON_4 83 GENERAL_BUTTON_4 83 BUTTON_4 83 EFFECTS_LEVEL 91 EFFECTS 91 TREMULO_LEVEL 92 TREMULO 92 CHORUS_LEVEL 93 CHORUS 93 CELESTE_LEVEL 94 CELESTE 94 PHASER_LEVEL 95 PHASER 95 DATA_BUTTON_INCREMENT 96 DATA_BUTTON_INC 96 BUTTON_INC 96 DATA_BUTTON_DECREMENT 97 DATA_BUTTON_DEC 97 BUTTON_DEC 97 NON_REGISTERED_COARSE 98 NON_REGISTERED_FINE 99 REGISTERED_COARSE 100 REGISTERED_FINE 101 ALL_SOUND_OFF 120 ALL_CONTROLLERS_OFF 121 LOCAL_KEYBOARD 122 ALL_NOTES_OFF 123 OMNI_MODE_OFF 124 OMNI_OFF 124 OMNI_MODE_ON 125 OMNI_ON 125 MONO_OPERATION 126 MONO 126 POLY_OPERATION 127 POLY 127
Events in the MIDI specification take bytes as a value, but some controllers can have a wider range of settings than is available in a byte. These controllers have a coarse and a fine setting.
However, when you want to set something like VOLUME, you shouldn't have to decompose the volume you want to set into a high byte and a low byte, and then set two controllers. With JFugue's Combined Controllers, you can simply say
X[Volume]=nnnn
, wherennnn
is some value between 0 and 214-1, or 16383. JFugue will figure out how much to set the coarse and fine controllers on its own (and, it will ultimately generate two separate Controller events - but you don't have to worry about that unless you're interacting directly with the parser).
BANK_SELECT 16383 MOD_WHEEL 161 BREATH 290 FOOT_PEDAL 548 PORTAMENTO_TIME 677 DATA_ENTRY 806 VOLUME 935 BALANCE 1064 PAN_POSITION 1322 EXPRESSION 1451 EFFECT_CONTROL_1 1580 EFFECT_CONTROL_2 1709 NON_REGISTERED 12770 REGISTERED 13028Other predefined constants
JFugue defines the following constants for your convenience. You can use them as values for setting controllers, as in
X[Hold_Pedal]=ON
.
ON 127 OFF 0 DEFAULT 64