Objectives

Students who complete this lab will demonstrate that they can:

In this lab, you’ll construct an object model of musical pieces with the ability to load parts of those pieces from files and to play all the parts together. The system, called the “Calgorythmic” music box, will load the parts using standard Java file I/O and it will play them using the Java Sound API. A key theme for the lab exercise will be the importance of assigning the appropriate responsibilities to each class in the model.

Music Notation and MIDI

Music is an ancient art form and musical notationwikipedia has developed into a rich and powerful system. Consider the following excerpt from the traditional song “Frère Jacques”wikipedia :

Frere Jacques

Here we see the time-honored, graphical way of specifying the pitches, relative durations and sequence of notes in a piece of music. Pitches are denoted by the location on the five-lined staff; durations are denoted by the format of the note’s notation; sequence is read left-to-right.

As with other media, digitizing music requires looking at the content in a more detailed way than one might commonly do. The Musical Instrument Digital Interfacewikipedia (MIDI) is a common music protocol that models a piece of music as a set of pitches with pitch starting and stopping events. It models playing a note on a piano as a three-step sequence of operations: pressing the piano key, waiting an appropriate amount of time and then releasing that key. This model is shown in the following figure:

MIDI notation

Here we see the first eight notes of Frère Jacques. On the top of the diagram we see the pitches C4, D4, and E4 (i.e., the forth C, D and E notes from the bottom of the piano), each played as quarter notes (i.e., roughly speaking one beat) in the given sequence. On the bottom we see the equivalent MIDI notation, which views the part as a sequence of Midi “events”. To model the first note, the Midi sequence specifies a C4 pitch-start event followed by a quarter-note-long wait event. For the second note, Midi specifies a C4 pitch-stop event, a D4 pitch-start event, and then another quarter-note-long wait event.

The MIDI Infrastructure

The classes you will use in this lab are shown in the following figure.

Midi and Calgorythmic Class Structure

These two packages serve the following purposes:

Take time now to review the complete API specification for these packages. Given this infrastructure, you can create a simple console-based program that plays pieces of music specified by your code.

Exercise 12.1

Create a new package for this lab ( edu.institution .yourLoginID .lab12 ) and load the initial code as follows:

  1. Add midi.jar from the standard course library to your main project’s build path (off-campus students can download this library from here: midi.jar);
  2. Import the two sub-directories from the standard code repository for this lab (i.e., calgorythmic and data) into your lab12 package (off-campus students can download these files from here: data.zip and calgorithmic.zip); NOTES:
    • When selecting an import source, choose "File System"
    • When choosing the directory, type in the path to the standard code repository. Make sure that the "From directory" listed goes all the way into the chapter 12 folder. Now, click browse, and then cancel. This will populate the left panel with a hierarchy from which you can choose to select only the calgorythmic and data folders.
  3. Modify the package specifications in the Java code files to match your own package and re-organize the import statements as necessary.

When done, your directory/package structure should look as follows:

edu
   institution
      loginID
          lab12
             calgorythmic
             data

Now, do the following:

  1. Make sure that you can play the middle C piece specified in the exercise0() method by running the CalgorythmicConsole application.
  2. Now, extend CalgorythmicConsole by adding an exercise1() method that plays the first 4 notes of Frère Jacques (i.e., C4 - D4 - E4 - C4 , all Midi.QUARTER notes). Base your new method on the exercise0() method.

Given the Calgorythmic API, you can program simple pieces of music using basic control structures. For example, to create and play a chromatic scale from Midi.C3 to Midi.C6 , you can use the following algorithm:

  1. Declare/initialize a new Piece ( chromaticScalePiece ) with tempo Midi.PRESTO.
  2. Declare/initialize a new Part ( chromaticScalePart ) with instrument Midi.PIANO .
  3. Loop for i from Midi.C3 up to Midi.C6
    1. Add a new Chord object to chromaticScalePart with pitch i and duration Midi.QUARTER .
  4. Loop for i from Midi.C6 back down to Midi.C3
    1. Add a new Chord object to chromaticScalePart with pitch i and duration Midi.QUARTER .
  5. Add chromaticScalePart to chromaticScalePiece .
  6. Play chromaticScalePiece .
Exercise 12.2

Add methods to CalgorythmicConsole that implement the following:

  1. A chromatic scale - using the algorithm given above;
  2. Extra-Credit: A random song - devise and implement your own algorithm for playing a 10 note (i.e., Chord) song where each note has a random pitch and a random duration (see the lecture notes for details on how to use the Java Random class);

Call your new method(s) exercise2 (and exercise2b for the extra credit).

Reading Parts from Files

Hard-coding pieces, as we have done so far, does not tend to scale well as the parts get longer and more complicated. Instead, we store the sequence of chords for a part in a carefully formatted text file and add a method to load that part from a file. This process is called parsingwikipedia .

As discussed in class, parsing data from external sources like files or the keyboard can be a complicated business. However, in this lab, we’ll stick with a simply formatted text file that has one line for each chord (e.g., see the melody part for Frère Jacques: FrereJacques.txt - found in the data directory downloaded earlier), and we’ll assume that the file is properly formatted.

The knowledge of how to parse a Part object has two key aspects:

Given these new constructors for Chord and Part , you can load and play the melody of Frère Jacques from FrereJacques.txt using the following algorithm:

  1. Declare/initialize a new Piece using the tempo Midi.ALLEGRETTO .
  2. Declare/initialize a new Part based on the chords specified in the following file: "src/edu/institution /yourLoginID /lab12/data/FrereJacques.txt"   (Note: Use the Part(String, int) constructor you just created and pass it the given filename and Midi.PIANO as the instrument.
  3. Add the new Part to the Piece.
  4. Play the new Piece.
Exercise 12.3

Build the parsing constructors for Chord and Part using the algorithms given above. Then create an exercise3() method, based on the algorithm just given, that loads and plays Frère Jacques from FrereJacques.txt (found in your data directory).

Working with Pieces of Music (Extra Credit)

Pieces of music are generally made up of multiple parts, say a melody and harmonies, or multiple copies of a part played as a round. The Calgorythmic classes you now have can load the melody of Frère Jacques and craft it into a 3-part round using the following algorithm:

  1. Declare/initialize a new Piece using the tempo Midi.ALLEGRETTO .
  2. Declare/initialize a new Part ( melody ) constructed using the Frère Jacques file used above, setting the instrument to Midi.PIANO .
  3. Declare/initialize three new Parts: round1 , round2 , round3 , all using the instrument Midi.PIANO .
  4. // Create a part for round 1
    Add the chords of the melody to round1 (using round1.addChords(melody.getChords()) ).
  5. Add four measures of rest to the end of round1 (using round1.addRests(4 * Midi.WHOLE) ).
  6. // Create a part for round 2
    Add two measures of rest to the beginning of round2 .
  7. Add the chords of the melody to round2 .
  8. Add two measures of rest to the end of round2 .
  9. // Create a part for round 3
    Add four measures of rest to the beginning of round3 .
  10. Add the chords of the melody to the end of round3 .
  11. Add all three rounds to the Piece.
  12. Play the Piece.
Exercise 12.4 (Extra Credit)

Build an exercise4() method that loads Frère Jacques from FrereJacques.txt and plays it as a three-part round.

Checking In

Submit the final version of your music player. We will grade this exercise according to the following criteria: