Problem Set 1: The Art of JFugue

Due: Tuesday, 31 August 2010 (3:30pm)

The goal of this problem set is to introduce you to the Java programming language and the tools we will be using in this class. In addition, the problem set will provide some exposure to object-oriented design and classes in Java.

Collaboration Policy. For this assignment, you should feel free to work with other students on setting up Java and Eclipse, creating your project, and installing the JFugue package. You should do problems 1-4 on your own, but may discuss the problems and get help from other students on these problems. For the optional problem 5, you may work with other students as you wish, but should should make sure to note all students who you worked with on your submission.

Background

Java and Eclipse

For all the problem sets in cs2220, you will want the Java runtime and the Eclipse IDE installed on your computer so that you can create and execute Java programs. These tools are installed on the CS lab and ITC lab machines, but if you want to work on the assignments on your own computer you should install them now.

Follow the directions on the course website (Programming in Java) to set up Java and Eclipse on your computer and create a new Java project named jfugue. (Yellow boxes like this one describe things you should do, but do not need to turn anything in for these steps.)

JFugue

Part of the richness of Java is the large number of libraries and APIs that are available for free. An API is an acronym for application programming interface. In general, an API provides a way for programs to interact with each other.

For this problem set, we will use the music generator JFugue (http://www.jfugue.org). JFugue is open source software, distributed under the LGPL license. This means the source code (written entirely in Java) is available for you to look at, modify, and adapt in your own programs as long as you credit the original authors and follow the other restrictions on the LGPL license. For this assignment, we will not modify JFugue itself, but just use the APIs it provides.

A nice feature of JFugue is that it allows a user to submit a pattern – a string – with a fairly simple syntax that is then converted to music. JFugue’s features are fairly extensive, as you’ll discover as you play with the code.

Install the two packages you need to use JFugue. The packages are:

To install each package, download the packages using the links above and save the files in your workspace (we recommend creating a lib subdirectory and saving all your packages there). Then, right-click on the project name (e.g., jfugue in ps1) in the Package Explorer and select Properties. This pops up the Properties Dialog. In the Properties Dialog, select the Libraries tab. Click Add External JARs…. Select the .jar file you want to install.

Creating a Java Class

Unlike Scheme and Python where you can create stand-alone procedures, in Java all procedures must be defined inside a class. A class in Java packages state (known as instance variables) and procedures (known as methods). A class also defines a datatype. Important goals of this class include understanding how to define classes well, learning to effectively break complex problems into classes, and reasoning about subtypes. For now, though, we will just create a class to be able to define a procedure.

Create a new class by right-clicking on src and selecting New | Class. The New Java Class dialog should appear. Enter the name of your class in the Name: box (we’ll use FuguFugue). For the Package Name: enter ps1. Under the Which method stubs would you like to create? question, check the public static void main(String[] args) box. Click Finish to create the class.

You should now see the FuguFugue.java file containing:

package ps1;

public class FuguFugue {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

Eclipse generated the stub main method. The main method is a special method that will be called when your program starts executing.

Modify this file by adding this line below the package ps1; line at the top of the file:

import org.jfugue.*;

This imports all of the jfugue classes into your namespace.


Next, add some code to the body of the main method:

	public static void main(String[] args) {
		Player player = new Player();
		player.play("C D E F G A B C6w");
	}

Select File | Save (or Ctrl-s) to save your file. Select Run | Run (or Ctrl-F11). You should hear a scale.

Understanding the Program

The first line declares an initializes a variable named player. It is initialized to a new Player object. The Player class is defined by JFugue. You can see its full interface in the JFugue documentation: http://www.jfugue.org/javadoc/org/jfugue/Player.html.

The Player class defines several methods that can be used to play music. The simplest one is to pass in a string to the play method. The string is what JFugue calls a MusicString. If you are a musician, you may be interested in all the things you can do with the MusicStrings. See the chapter from the JFugue book: http://www.jfugue.org/jfugue-chapter2.pdf (it is not necessary to read this, though, to complete this problem set).

The next line, player.play("C D E F G A B C6w"); invokes the play method on the player object created by the previous line. Method invocation is similar to calling a procedure, except the object is used before the method name. The most comparable Scheme syntax would be (play player "C D E F G A B C6w"). The parameter to the method is a String object. The java.lang.String datatype is built-in type for representing an immutable sequence of characters. Here, we create a String object using the special literal syntax, just putting the contents of the string in double quotes.

Experimenting with Java and JFugue

Copy the code below into your FuguFugue.java file, replacing the class definition as follows:

package ps1;
import org.jfugue.*;

public class FuguFugueOrig {
	private static String tune = "D Gqi F#i G B Aqi Gi A B Gqi Gi B D6 E6h Rq "
		+ "E6q D6qi B5i B5 G5 A5qi G5i A5 B5 G5qi E5i E5 D5 G5w+D5w+G4w";

	public static void playOldSong() {
		Player player = new Player();
		player.play("T125 I[GUITAR] " + tune);
	}

	public static void main(String[] args) {
		playOldSong();
	}

}

It plays a more interesting song that the scale in the first example, and puts the song in a separate method which is called by the main method.

Problem 1. Modify the program to repeat the song forever. You should do this at least two different ways: (a) by using a recursive procedure call (which you should be very familiar with already from cs1120), and (b) by using a looping statement (see the control flow tutorial). (Note that if you do this correctly, the only way to stop it is to terminate the program execution. You can do this by selecting Window | Show View | Console and clicking on the red square in the title bar for the Console window.)
Problem 2. Even the most die-hard wahoo may not want to hear the song continuously forever. Create a new method that takes a integer as a parameter, and plays the song that number of times. The prototype for your procedure should be:
public static void playOldSong(int n) { ... }.

To test your solution to Problem 2, you should modify the main procedure to pass in the parameter to playOldSong. The argument to main is an array of String objects that corresponds to the command line arguments to your program (Section 2.3 of the textbook introduces arrays). So, the first argument is args[0]. The problem is this argument is a String, and for the parameter to playOldSong we need an int (integer). The java.lang.Integer class provides the parseInt(String) static method that takes a String object as its input and returns an int object with the corresponding value. Thus,

     int num = Integer.parseInt(args[0]);

will initialize the integer variable num to the value corresponding to the first program argument. To set the program argument in Eclipse, select Run | Run Configurations which pops-up the Run Configurations dialog. Select the (x)= Arguments tab and enter the arguments you want in the Program arguments box.

Few wahoos are able to maintain a constant tempo as their enthusiasm brims while singing the song, so we want a way to increase the tempo. The T125 at the beginning of the music string sets the tempo to 125 beats per minute. By changing the number after the T we can set the tempo to any integer value. You can concatenate strings using the concatenation operator (+) like this:

     System.out.println("My favorite number is " + 2220);

The System.out.println method takes a String object as its input and prints out that string to the Java console. You may find it useful to use System.out.println to print the music string for Problem 3 so you can see it is correct.

Problem 3: Up-ing the Tempo. Define a method, void playOldSongTempo(int), that takes as input an integer representing a tempo in beats-per-minute and plays the song at the requested tempo. To test your method, modify the main method to call playOldSongTempo(int) with the command line argument.
Problem 4: Accelerating the Song. Define a method, void accelerateSong(String tune, int repeats, int tempo, double rate) that takes as input a music string representing a tune, an integer representing the number of repetitions, an integer representing the starting tempo, and a floating point number (double is a primitive type for a 64-bit floating point number) representing the rate of tempo change for each repetition. For example, if the tempo argument is 120 and the rate is 1.1, each repetition should increase the tempo by 10%.

Demonstrate your accelerateSong method by repeating the old song 5 times with tempo starting at 120 beats per minute and increasing 25% each repetition: accelerateSong(tune, 5, 120, 1.25); (where tune is a String variable initialized to the value of the song.

Note that the value after the T in a music string must be an integer. You can find the integer nearest a given floating point number using int Math.round(float). For example, Math.round(2.8) evaluates to the integer 3.

Everything below here is optional. It is not necessary to do anything beyond this point to receive full credit on this assignment.

Problem 5 (optional). Define methods that transform a tune in more interesting ways. You can do anything you want for this, but here are a few ideas and hints:

  • Use java.util.Random.nextInt(int n) to incorporate psuedo-randomness into your music. You could adjust the tempo, instrument, or even the notes pseudo-randomly using these values.
  • Define a method that reverses the order of the notes in a music string.
  • For the musically talented, define a method that transposes a music string or adds harmony to it.
Submission: bring to class a stapled, printed submission containing your answers to questions 1-4 (and optionally question 5). Your submission should include all the code you write, clearly marked for each question.
The original JFugue problem set was developed for cs2220 Fall 2008 and Fall 2009 by Paul Reynolds, and developed for Fall 2010 by David Evans.