Ordering Phrases Around: Random Phrase Positioning

In this tutorial a number of cheezy melodies are arranged in a random order.  Try to ignore the cheese, and ponder the compositional possiblilities!

Here is an example output from the class.

Click here for the source file: Arrange.java

Lets have a closer look at the Arrange class.  First of all, the import declarations let us import classes from various packages so that we can use them:

import jm.music.data.*;
import jm.music.tools.*;
import jm.JMC;
import jm.util.*;


Why do we need to import and implement JMC?:

/**
* Generates phrases and places them in a random order within parts.
* @author Andrew Brown
*/

public final class Arrange implements JMC{
public static void main(String[] args){
//Create the data objects we want to use
Score score = new Score("An Arrangement");
//Parts can have a name, channel, and instrument.
Part melodyPart = new Part("Melodies", CLARINET, 0);


If we implement JMC, it gives us acess to a whole heap of variables such as CLARINET and FLUTE. These variables represent the General MIDI number for that instrument.  Using variables that have meaningful names is often easier than trying to remember the number of the instrument.  eg "what was the glockenspiel soud again? 14... or was it 36... hmm."

You can observe the JMC variable "CLARINET" being used on the last line of the code above.

The next bit is the guts of the "random arrangement process" - try and work out whats going on:

                //Add the phrases to an array
Phrase[] allPhrases = {phrase1, phrase2, phrase3};


The strategy that we will take is to arrange the Phrases using a random number.  
Knowing that a number will need to select a certain Phrase, we need to put the Phrases into an array.  
In this case the array is called "allPhrases", so if we want to access one of the phrases in this array, we can go "allPhrases[0]" or "allPhrases[1]" or "allPhrases[2]".

So now all we have to do is make a random number and get it to select a certain Phrase - 20 times. (you can set it to be anything you want - however, considering the cheezyness, I would recommend you not to try any amount above 20)

Can you see the 20?  Try changing it.

               
//randomly arranage the phrases into a part
int r;
double addTime =0.0;
for(int i=0; i<20;i++){
//select a random phrase
r = (int)(Math.random() * allPhrases.length);

//print to the screen which one was chosen
System.out.println("Phrase "+i+" is phrase number "+ r);
// add a copy of the chosen phrase to the part
melodyPart.addPhrase(allPhrases[r].copy());

}


(note: the extra System.out.println("") statements that appear in the code have been removed from this example to make it appear less confusing.)

So the 
for(int i=0; i<20;i++)
statement signifies the start of a loop.  The variable "i" lives and dies within the scope of the loop.  It starts off at 0, but living rather recklessly "i" is dead by age 20, due to the fact that when "i<20;" the loop ends. "i++" increments it at the end of each loop.  We will use "i" later.

Now we should try and work out how the selection process within the loop operates.  

Math.random() generates a random number between 0.0 and 1.0.  

Because there are three Phrases in the array, "allPhrases.length" will return 3.

So if we multiply the raw random result by 3, we get a number between 0.0 and 3.0.  

Then if we want to round it down, we can cast it as an integer by going: "(int)(number to convert to integer)".  Casting to an int rounds down always, so we know that we have a random integer: 0, 1 or 2.  

We can then plug this integer in: "allPhrases[r]" to select the Phrase.

To explain the last line of the example above: we are making a copy of the selected Phrase, and adding it to the Part.  The ".copy()" method returns a new object that has exactly the same properties as the one that called ".copy()".  If you didn't do this, you wouldn't be adding a separate, new Phrase each time.  

The last bit is peanuts.  Read the comments! (//)

               
//add part to the score
score.addPart(melodyPart);

//set the tempo
score.setTempo (130.0);

//OK now write to a MIDI file
Write.midi(score, "Arrangement.mid");

//display
View.show(score);
}
}