Scatter Phrases: Stochastic phrase positions

This tutorial creates phrases across 16 channels and sets their start positions at random over 100 beats. Being stochastic (random) for both note pitch and phrase position means that every time this program is run the results are quite unique. There are moments in the pieces where the texture is quite thick and the mood intense and other moments where the texture is sparse and the mood delicate.

Here is an example of the output from the Scatter class.

Below is the source code for the last example.

Click here to view source.

Lets have a closer look.

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


/**
* This class scatters phrases over 100 beats or so.
* @ author Andrew Brown
*/


public final class Scatter implements JMC{

/**
* The main method, where all good Java programs start
*/

public static void main(String[] args){
Score s = new Score();

// loop through 16 parts
// incrementing the instrument and channel each time

for(int i=0; i<16;i++) {
Part p = new Part("part",i,i);

// create a couple of phrases in each part

for(int j=0; j<2;j++) {
Phrase phrase = new Phrase();
// Use the makePhrase method (below)
phrase = makePhrase();
p.addPhrase(phrase);
}
s.addPart(p);
}

// provide some rhythmic structure by
// accenting particular beats

double[] accentArray = {0.0, 1.0, 1.5, 1.75, 3.0};
Mod.accents(s, 4.0, accentArray);
View.show(s);
Write.midi(s, "TestMIDI.mid");
}

/**
* This method generates a phrase based on a random walk
*/

private static Phrase makePhrase() {
Phrase phr = new Phrase((Math.random()*400) * SQ);
int pitch = (int)(Math.random()*60+30);
for(int i=0;i<50;i++) {

//randomly shift the pitch
pitch += (int)(Math.random()*10-5);

// if the pitch walks out of the bounds, put it back to 60
if(pitch <6 || pitch > 94) pitch = 60;

//make the note, with random velocity to make it interesting
Note n = new Note(pitch, SQ, (int)(Math.random()*70
+ 30));

//add note to phrase
phr.addNote(n);
}
return phr;
}
}
A brief explanation of the code is that it creates 16 parts, in each part there are two phrases. The phrases have a random start time,
Phrase phr = new Phrase((Math.random()*400) * SQ);

The start time is multiplied by a Semiquaver so that a phrase always starts on a semiquaver subdivision. This stochastic generation of the phrase start time is what spreads the phrases over the music creating a changing, but overall similar, texture.

You will notice how the word "makePhrase()" is used to fill the Phrase "phrase".


for(int j=0; j<2;j++) {
Phrase phrase = new Phrase();
// Use the makePhrase method (below)
phrase = makePhrase();
p.addPhrase(phrase);
}

You will also notice that there is another method in this class that is not a main method.  It is called makePhrase():

 	/**
* This method generates a phrase based on a random walk
*/

private static Phrase makePhrase() {
Phrase phr = new Phrase((Math.random()*400) * SQ);
int pitch = (int)(Math.random()*60+30);
for(int i=0;i<50;i++) {

//randomly shift the pitch
pitch += (int)(Math.random()*10-5);

// if the pitch walks out of the bounds, put it back to 60
if(pitch <6 || pitch > 94) pitch = 60;

//make the note, with random velocity to make it interesting
Note n = new Note(pitch, SQ, (int)(Math.random()*70
+ 30));

//add note to phrase
phr.addNote(n);
}
return phr;
}
}

As the code is executing, it goes through each line, from top to bottom.  When it gets to

        	        	phrase = makePhrase();

It goes straight into the makePhrase method.  In the makePhrase method, it makes a new Phrase, and returns it to the place where "makePhrase()" was called.  Programs are organised like this so that you can organise things more easily and reuse code multiple times.

Now for the actual algorithms:

The notes in each phrase start at a random pitch between 30 and 90 (60 + 30),

int pitch = (int)(Math.random()*60+30);

Pitch movement is by a random interval from note to note (a Random walk),

pitch += (int)(Math.random()*10-5);

Becase this happens 50 time, the chances are that the pitch will eventually exceed it's boundaries.  The MIDI range for pitch is 0-127.  If it goes above this or below it, we will get errors.  If you want to change the boundaries, just edit the line:

if(pitch <6 || pitch > 94) pitch = 60;

This says: if the pitch becomes lower than 6 (just one step away from becoming negative) or higher than 94 (you can set this to be as high as 122 if you like!), set it back to 60, which is middle C.