Introduction
In this guide, we will learn how to create and manipulate chords and chord progressions, how to use setKey()
, distribute()
and allChordsAs()
methods of the ChordProgression
class, and how to play different patterns simultaneously by using voices in JFugue.
This is the second part of the three-part tutorial series, in which we are trying to re-create the intro of the jazz version of Sunday Morning by Maroon 5. But the steps provided in the articles, are easily applicable to any other song creation process as well.
In the previous part of the series, we covered the fundamentals of the JFugue library, learning how to use notes, octaves, durations, tempo, instruments, and patterns. At the end of the first article, we created the intro vocals without any chords. By the end of this tutorial, our song will have the chords ready to play along with the vocals.
In the final part of our tutorial series, we will learn about Rhythms in JFugue. This will allow us to build and play the rhythms on top of the previous parts. We will also take a look at how to save our music to a MIDI file using the JFugue as well as to read music from a MIDI file using the JFugue library.
If you want to check out other parts of the series, here are the links:
- JFugue Beginners Guide Part I: Notes, Durations, Patterns
- JFugue Beginners Guide Part II: Chords and Chord Progressions (here)
- JFugue Beginners Guide Part III: Rhythms, Reading and Writing to MIDI
Chords and Chord Progressions in JFugue
When it comes to chords, JFugue offers multiple ways to create them. First, let's take a look at how to create our very own chords by combining the notes one by one.
We will create the D-Minor7 chord, which also happens to be the first chord of our song. This chord consists of four (4) notes that we can combine and play simultaneously:
player.play("D+F+A+C");
That works well for now but it can become a very tedious job to create every single chord note by note. In this song, we have three (3) chords (Dm, G, C) with 3 (DMin9, GMaj13, CMaj9) inversions.
We don't necessarily have to create all chords manually. You can create your chords using ChordProgression
if you're familiar with music theory. To do so, we'll import and instantiate the ChordProgression
class with the chord progressions of our chords:
import org.jfugue.theory.ChordProgression;
ChordProgression cp = new ChordProgression("ii V I");
We can also set the key of the chord progression by chaining setKey()
method to it:
ChordProgression cp = new ChordProgression("ii V I")
.setKey("C");
We can play chord progressions just as same we did with patterns:
player.play(cp);
ChordProgression
implements PatternProducer
, which, as the name suggests, produces patterns. And when we pass ChordProgression
into the Player.play()
method, the method asks for the pattern from ChordProgression
and plays it just as same it does with the patterns.
Another effective method of the ChordProgression
is distribute()
. This method allows us to distribute a musical feature along with the chords inside of a ChordProgression
object.
At the moment our chords in cp
are Dm, G, and C.
Let's change all chords to 7th using distribute()
:
ChordProgression cp = new ChordProgression("ii V I")
.setKey("C")
.distribute("7");
player.play(cp);
Another essential change would be to set the duration of each chord and to add some 'Rest' in between the chords. Using allChordsAs()
method, we can select each chord in cp
by typing $
with an index number of the chord:
ChordProgression cp = new ChordProgression("ii V I")
.setKey("C")
.distribute("7")
.allChordsAs("$0hqit Ri $1hqi Ri $2wh Rht");
We can think of $0
, $1
, and $2
as placeholders that refer to the ii
, V
, and I
respectively. Any modifications that we apply to them are applied to the chords in cp
. Go ahead and play to see the difference.
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Another cool thing about ChordProgression
is that we can easily convert it to the Pattern
and use Pattern specific methods to modify it even further:
Pattern cpPattern = cp.getPattern();
System.out.print(cpPattern);
player.play(cpPattern.setTempo(180).setInstrument("DRAWBAR_ORGAN").repeat(4));
With the getPattern()
method, we convert the cp
to a Pattern
instance, then we print the current chords in the cp
so that we can see the chords being filled in. Finally, we set the tempo, the instrument, and the repeat value.
The chords that JFugue plays look like:
D4MIN7hqit Ri G4MAJ7hqi Ri C4MAJ7wh Rht
ChordProgression
provides a range of possibilities, but as mentioned before, it requires some knowledge of musical theory. If don't know much about music theory but have basic knowledge of chords, then you can conveniently use chords inside the patterns.
To get the full potential of the Staccato, which is proud to be human-readable, we will write our chords directly into the pattern:
Pattern mainChords = new Pattern("T180 D4Min9hqit Ri G4Maj13hqi Ri C4Maj9wh Rht");
Let's break D4Min9hqit
down. "D" is the name of the chord, followed by the "4" which is the number that represents the octave, followed by "Min9" which stands for "Minor 9th", and followed by "hqit" which are the duration measurements.
We can take advantage of the Pattern
class and add some more chords to the pattern by chaining the .add()
method:
mainChords.add("D4Minhqit Ri 4Majhqi Ri C4Majwh Rht");
Notice that we didn't specify the tempo in the second part of the pattern, since setting the tempo once is enough to apply it for all of the following musical events.
In the real world, not every instrument in a song plays in sequential order. Now that we have our chords playing properly, we would like to add some other patterns to play along with it, not to append directly to it, like we did with add()
.
JFugue provides a special token called 'Voice'. Most of the songs are made of layers of patterns. For instance, the piano keeps playing chords while the drumbeat goes on and vocals sing along them. In JFugue, the 'Voice' token represents each of these individual players/singers, allowing them to play together, play at the same time.
We can use up to 16 different voices, which is the sum of the standard MIDI channels. Voice numbers can range from V0
to V15
. We can populate voices with any instruments we'd like. Except for the 10th channel or V9
. This special voice layer is reserved for the percussion by default and can have different sets of percussion instruments and layers at V9 (more on that later).
Let's try to recreate the intro of the 'Sunday Morning' (Jazz version) by adding new voices to our current mainChords
:
Pattern mainChords = new Pattern("T180 V0 D4Min9hqit Ri G3Maj13hqi Ri C4Maj9wh Rh");
mainChords.add("D4Minhqit Ri G4Majhqi Ri C4Majwh Rht");
Pattern pianoTouch = new Pattern("T180 V1 Rw | Rw | Rhi | G4qi G3s A3is CMajis ri");
pianoTouch.add("Rw | Rw | Rhi | G4s C5wa100d0");
player.play(mainChords, pianoTouch);
The mainChords
pattern is the same as it was before. We've added a new pattern pianoTouch
and set it to the second voice channel V1
. Since these notes occurred at the end of each chord loop, we had to hold them using Rw
to play right at the correct time. You may have noticed that the final note of the pianoTouch
pattern has this weird token a100d0
glued to the whole note of C. That token represents the attack velocity and the decay velocity of the note.
We have set the attack value to 100, making our note sound a bit louder than the others, and have set the decay value to 0, which caused our note volume to decrease to zero very quickly. You can set either of them and none of them on your preference to any value between 0 to 127.
The part that we composed at pianoTouch
plays only once in the original song. So, we want to make sure that while the mainChords
plays on repeat, the pianoTouch
doesn't repeat.
We can create a new pattern introOnce
to group our other patterns. This way we can arrange what to play once and what to play on repeat. Replace the line that calls play()
with these two lines:
Pattern introOnce = new Pattern(mainChords, pianoTouch);
player.play(introOnce, mainChords.repeat(2));
This should play the pianoTouch
once, and repeat the mainChords
2 more times afterward.
Our song is coming along great! Now it's time to help the dancers, we will use the Rhythm
class to guide them in the next part of the series!
Conclusion
In this tutorial, we learned how to use chords and chord progressions in the JFugue library. We also covered setKey()
, distribute()
and allChordsAs()
methods of the ChordProgression
class, how to play different patterns simultaneously by using voices, and how to apply attack/decay properties to notes or chords.
In the next and final part of the article series, we will learn how to create and use the rhythms in JFugue. By doing so, we will be able to finalize our song. We will also cover how to save our song into a MIDI file format using JFugue, as well as how to import a MIDI file and read content into the Staccato format.
You can continue to read the next part: JFugue Beginners Guide Part III: Rhythms, Reading and Writing to MIDI.
Or if you need more details about the fundamentals of JFugue, you can check out the first article to refresh your knowledge: JFugue Beginners Guide Part I: Notes, Durations, Patterns.