JFugue Beginners Guide Part III: Rhythms, Reading and Writing to MIDI - Stack Abuse

JFugue Beginners Guide Part III: Rhythms, Reading and Writing to MIDI

Introduction

In this tutorial, we will learn how to create rhythms using the Rhythm class, how to use JFugue's built-in RhythmKit to conveniently create rhythm, and how to apply different rhythm instruments to our song. We will also cover how to save our music to a MIDI file using the JFugue, and how to read music from a MIDI file using the JFugue library.

This is the third and final part of the three-part guide 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 first 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 previous part of the series, we learned how to use chords and chord progressions in the JFugue library. We also covered how to use 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 and/or chords.

Here are the links to the previous parts of our JFugue tutorial series:

Rhythms in JFugue

JFugue lets us use rhythms with the built-in Rhythm class. This class provides an intuitive way to interact with the rhythm tokens to create the beat we want. As mentioned before, V9 is the predefined voice channel for all percussion. So any object that we create from this class, will be added to V9 by default.

To use the Rhythm class, we must first import it:

import org.jfugue.rhythm.Rhythm;

Then we instantiate it to add layers:

Rhythm rhythm = new Rhythm()
        .addLayer("O..oO...O..oOO..")
        .addLayer("..S...S...S...S.")
        .addLayer("````````````````")
        .addLayer("...............+");

player.play(rhythm.getPattern().repeat(2));

Run the code to play this cool beat which is also available on the official JFugue website.

The string that the Rhythm class takes in, may seem a little different at the first glance, but consider that it converts them all back to the Staccato on the back. And by using the getPattern() method we can and turn them into a Pattern object and use pattern-specific methods, such as repeat(). The addLayer() method works similarly to the Voices. You can think of each layer as an equivalent of Voice, except since we are already in a voice (V9) we can't add any, but instead, we add layers up to 16.

To elaborate, each of the characters that are passed into the class, represent an instrument or the Rest from the JFugue's default RhythmKit. Here you can examine each instrument that corresponds to the characters in the above example:

Duration Character
. Ri
O (uppercase) [BASS_DRUM]i
o (lowercase) Rs [BASS_DRUM]s
S (uppercase) [ACOUSTIC_SNARE]i
s (lowercase) Rs [ACOUSTIC_SNARE]s
^ (caret) [PEDAL_HI_HAT]i
` (backtick) [PEDAL_HI_HAT]s Rs
* (asterisk) [CRASH_CYMBAL_1]i
+ (plus) [CRASH_CYMBAL_1]s Rs
X (uppercase) [HAND_CLAP]i
x (lowercase) Rs [HAND_CLAP]s

This way of producing rhythms may look fun and tidy, but it's hard to compose a jazz rhythm with it. For starters, it is a lot less readable, also the durations are fixed unless you use patterns to manipulate it (like we did with Chord Progressions).

Fortunately, JFugue also lets us use the rhythm tokens with good old Patterns! Here, we will add rhythms to a pattern using a Staccato string:

Pattern introRhythm = new Pattern("T180 V9 [CLOSED_HI_HAT]x Rx [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt");

It is very similar to what we've done before, except this time we don't use the I token in front of every instrument, we just pass the percussion instrument name. Each instrument name is followed by an x token which as you might remember is the duration token for the Sixty-fourth length of a full note. The rest should look pretty familiar.

Let's play this with our previous chord and intro patterns:

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");
Pattern introOnce = new Pattern(mainChords, pianoTouch);

player.play(introOnce, introRhythm.repeat(8));

That's the first part of the intro, now we'll add some BASS_DRUM to create our main rhythm that should play throughout the whole song (at least for the most part). Add this after playing the first intro:

Pattern mainRhythm = new Pattern("T180 V9 [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt  [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt "
);

It sounds better than it looks. Let's give it a try:

Pattern introSecondPart = new Pattern(mainChords, mainRhythm.repeat(2));

player.play(introSecondPart);

Check our GitHub repository to see the complete percussion instruments list

Let's also add a Bass Guitar to finalize our music:

Pattern bassGuitar = new Pattern("T180 V3 I[SLAP_BASS_1] D3is D3s Rhq G3is G3s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq | D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq G3is G3s Rq A3s Ri G3s E3q ");
bassGuitar.add("D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq D3is D3s Rhq G2is G2s Rqis B2qi C3is C3s Rhq G3i Ri A3q G3is F3s E3q ");

player.play(bassGuitar);

Before we add the bass guitar into any patterns, we need to decide when we want it to play. We don't want it to start playing right away, instead, it would sound a lot better if it started with the introSecondPart.

Well, we can't use the same trick as we did with the pianoTouch, at least not exactly. We can add a pattern of silence, long enough to get it throughout the introFirstPart and add the bass line to it, like so:

Git Essentials

Check out this hands-on, practical guide to learning Git, with best-practices and industry-accepted standards. Stop Googling Git commands and actually learn it!

Pattern bassGuitarSilence = new Pattern("T180 V3 Rw Rw Rw Rw | Rw Rw Rw Rw | Ri");
bassGuitarSilence.add(bassGuitar);
player.play(bassGuitarSilence.repeat(2), introSecondPart.repeat(8));

But then we wouldn't be able to play it on repeat because it would cause the same amount of silence to pass for each time our bass guitar is played. Instead, we will pass the bassGuitarSilence and bassGuitar separately, without using the add() method, but still leaving both in the same voice channel.

This way, one will have to wait until the other finishes playing:

player.play(bassGuitarSilence, bassGuitar.repeat(4), introSecondPart.repeat(8));

That's about it. Now all there is to left is to combine vocals and chords we've created in the previous parts of our tutorial series, with our rhythms to conclude the intro of our song.

I also made some fine-tuning here and there for durations to sync the music to the beat, so here's the final version:

import org.jfugue.player.Player;
import org.jfugue.pattern.Pattern;

public class MyMusic {
    public static void main(String[] args) {
        Player player = new Player();
        Pattern mainChords = new Pattern("T180 V0 D4Min9hqit Ri G3Majhqi Ri C4Maj9wh Rht ");
        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 Rw ");

        Pattern introOnce = new Pattern(mainChords, pianoTouch);

        Pattern introRhythm = new Pattern(
                "T180 V9 [CLOSED_HI_HAT]x Rx [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt ");

        Pattern introFirstPart = new Pattern(introOnce, introRhythm.repeat(8));

        Pattern mainRhythm = new Pattern(
                "T180 V9 [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt  [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt ");

        Pattern vocalsSilence = new Pattern("T180 V4 Rw Rw Rw Rw | Rw Rw Rw Rw | Rq ");

        Pattern vocals = new Pattern("T180 V04 ");
        vocals.add("I[TROMBONE]  Rh G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs");
        vocals.add("I[ALTO_SAX] C4i A5q G5isa50d0 Rs A5s E5i D5is Rs C5qis");
        vocals.add("I[TROMBONE] Rqi A4s G5i E5i Rs | G5is Rs E5q | D5is C5i Rs C5q G4q Ri");
        vocals.add("I[TRUMPET] G3is A3s C4is D4s C4is D4s G4is A4s G4is A4s | E4q rs F4h");
        vocals.add("I[TROMBONE] G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs A5is rs G5q A5s E5i D5i ri C5h Rit");
        vocals.add("I[TROMBONE] C5s A3q C5i Rs | D5i Rs Eb5qs Rs | D5q Eb5i Rs D5is Eb5s D4q Rs | C5i A4q C5h Rw Rhi");

        Pattern introSecondPart = new Pattern(mainChords, mainRhythm.repeat(2));

        Pattern bassGuitarSilence = new Pattern("T180 V3 Rw Rw Rw Rw | Rw Rw Rw Rw | Rq ");
        Pattern bassGuitar = new Pattern(
                "T180 V3  I[SLAP_BASS_1] D3is D3s Rhq G3is G3s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq | D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq G3is G3s Rq A3s Ri G3s E3q ");
        bassGuitar.add(
                "D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq D3is D3s Rhq G2is G2s Rqis B2qi C3is C3s Rhq G3i Ri A3q G3is F3s E3q ");

        Pattern introThirdPart = new Pattern(introFirstPart, bassGuitarSilence, bassGuitar.repeat(2), vocalsSilence,
                vocals.repeat(2), introSecondPart.repeat(4));
        player.play(introThirdPart);
    }
}

Feel free to improve it, or to continue composing the whole song since now you know almost everything you need to know!

Save Music to a MIDI File Using JFugue

With the right amount of time and effort, you can create great MIDI songs with JFugue. Great music is even better when shared with friends and loved ones. To share our musical composition, we will use JFugue's savePatternToMidi() method to convert our patterns to a MIDI file.

To save our music into a MIDI, first, we need to import MidiFileManager and then pass in the file path along with our pattern(s):

import org.jfugue.player.Player;
import org.jfugue.pattern.Pattern;

public class MyMusic {
    public static void main(String[] args) {
        // Our patterns…
        try {
            File filePath = new File("path/to/your/midi");
            MidiFileManager.savePatternToMidi(introThirdPart, filePath);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Check the file path to confirm that your MIDI is ready to use.

Read Music From a MIDI File Using JFugue

Similarly, we can also read a MIDI file and convert it to patterns. We will use the loadPatternFromMidi() method to pass in the file path of a MIDI and read the content.

Note that we will also need to handle the IO exception:

import org.jfugue.midi.MidiFileManager;

public class MyMusic {
    public static void main(String[] args) throws IOException {
        Pattern loadedFile = new Pattern();
        try {
            File filePath = new File("C:\\Users\\Ruslan\\Desktop\\MySundayMorning.midi");
            loadedFile = MidiFileManager.loadPatternFromMidi(filePath);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
        System.out.println(loadedFile);
    }
}

And this concludes our three-part tutorial series of the JFugue library.

Conclusion

In this tutorial, we covered how to create and use rhythms in JFugue using the Rhythm class and how to use JFugue's built-in RhythmKit to conveniently create rhythms. We also learned how to create rhythms by using Patterns with Staccato strings, and how to apply different rhythm instruments to our song. Finally, we covered how to save our music to a MIDI file using the JFugue, and how to read music from a MIDI file using the JFugue.

You can check out the previous article to learn about the chords and chord progressions also to learn more about the voices, attack, and decay features: JFugue Beginners Guide Part II: Chords and Chord Progressions.

Or if you need more details about the fundamentals of JFugue such as notes, octaves, durations, and patterns, you can check out the first article: JFugue Beginners Guide Part I: Notes, Durations, Patterns.

Last Updated: May 5th, 2021

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Ruslan HasanovAuthor

Full-stack software developer.
Python, C#, Linux.

Want a remote job?

    Prepping for an interview?

    • Improve your skills by solving one coding problem every day
    • Get the solutions the next morning via email
    • Practice on actual problems asked by top companies, like:
     
     
     

    © 2013-2021 Stack Abuse. All rights reserved.