HelperGUI

This tutorial introduces a class that provides a simple graphical interface that helps speed up the process of testing compositional algorithms.

This HelperGUI utility is designed to be extended by user classes. It provides a simple graphical interface that speeds up the cycle of composing-auditioning-recomposing by minimising the need for recompiling simple changes. It is especially useful for novice Java programmers as it enables the use of a graphical front-end to jMusic with minimal coding (and no interface coding at all!).

To use the HelperGUI class write a standard jMusic class with a main() method and a constructor. Make a super() call in the constructor. Overwrite the compose() method [which returns a Score object] and include the compositional logic in that method.

To render a score as an audio file, an Instrument array needs to be declared and assigned to the value 'insts' - which is already declared in the HelperGUI class. As in this example code fragment:

            Instrument sine = new SineInst(44100);
Instrument[] instArray = {sine};
insts = instArray;

There are five variables each with a slider that can be accessed to change values in the composition. Each variable, named variableA -> variableE, return integer values between 0 and 127.

 

The HelperGUI class is in the qt (quicktime) package of jMusic because it supports quicktime playback (therefore requires quicktime java to run). Those running systems where qt is not supported (Linux for example) may be able to remove the quicktime specific code from the source - or build your own similar GUI.

 

The HelperGUI class can be extended by a jMusic class,
and will appear similar to this:

Helper GUI screen shot
View / Download source - HelperTest source code

Let's have a closer look. 
  import jm.JMC;
import jm.music.data.*;
import jm.midi.*;
import jm.util.*;
import jm.audio.*;
import jm.gui.helper.HelperGUI
 
/**
* @author Andrew Brown
*/

 
public final class HelperTest extends HelperGUI implements JMC{
public static void main(String[] args){
new HelperTest();
}

public HelperTest() {
super();

setVariableA (10, "Range");
setVariableB(
60, "Note length");

}

public Score compose() {
Score s = new Score("Test");
Part p = new Part("Guitar", 0, 0);
Phrase scale = new Phrase();

//create the phrase note by note

for(int i=0;i<12;){
int pitch = C4+(int)(Math.random() *
variableA + 1) - variableA / 2;
if (pitch>=0&&pitch<=127){
//check to see if in valid range
Note n = new Note(pitch, DEMI_SEMI_QUAVER *
(int)(Math.random()*variableB + 1));
scale.addNote(n);
i++;
}
}
p.addPhrase(scale); s.addPart(p);   // set up the audio instrument array for rendering Instrument sine = new SineInst(44100); Instrument[] instArray = {sine}; insts = instArray; // send the score to the HelperGUi class for its use return s; } }

The HelperTest class imports the qt.*; package - this is required to access the HelperGUI class.

The class declaration line includes 'extends HelperGUI' to indicate that it should inherit the functionality of the HelperGUI class - including the ability to draw the user interface.

The main method simply class the constructor, which in turn makes a call to the HelperGUI constructor. Becuse the HelperTest class extends the HelperGUI class, the HelperGUI class is referred to as the HelperTest's 'super' class.

The HelperTest class (to take advantage of the GUI - Graphical User Interface) must include a public compose() method that returns a Score. The HelperGUI class expects this method to be there and will not operate correctly without one. In Java-speak we are overriding the compose() method of the super class.

In the compose() method a score is created - any way you like - and is computed and returned to the HelperGUI class each time you click the 'Compose' button on the GUI.

The HelperGUI includes five assignable sliders. Two are used in this example, variableA and variableB are integer variables declared by the super class and availible for access by any extending classes. Their value will be updated as the sliders on the GUI are moved. This allows you to try a few different settings for your compositional algorithm without needing to recompile and run. The variableA -> variableE values are all integers from 0-127, so you may need to do some simple math to scale or change type for use in your compositional algorithm.

In order to use the rendering option - which saves jMusic scores as audio files using instruments you create - you need to declare an instrument array. In this example, an array of one instrument, called sine, is set up then the locally declared array 'instArray' is assigned to the 'inst' variable of the super class. This is necessary so the HelperGUI class knows which audio instruments to use for rendering.

Using more of the Variable sliders

This class below uses the variable sliders to determine the probability of various drum rhythms and (variableE) the tempo. The variables are set to initial values in the constructor, then can be changed from the GUI at run time. Note that the variables are multiplied and divided to get into the appropriate range, and that we make use of the fact that in Java division of an integer by a double results in a double value.

import jm.JMC;
import jm.music.data.*;
import jm.midi.*;
import jm.util.*;
import jm.audio.*;
import jm.gui.helper.HelperGUI;   /** * @author Andrew Brown */
 
public final class Prob extends HelperGUI implements JMC{
public static void main(String[] args){
new Prob();
}

public Prob() {
super();
setVariableA(100,"Kick down beat prob.");
setVariableB(95,"Main snare & hat prob.");
setVariableC(70,"Hat off-beat prob.");
setVariableD(5,"Kick and Snare off-beat prob.");
setVariableE(60,"Tempo");
}

public Score compose() {
Score s = new Score("Test");
Part p = new Part("Drums", 25, 9);
Phrase kPhrase = new Phrase("Kick drum",0.0);
Phrase sPhrase = new Phrase("Snare drum",0.0);
Phrase hPhrase = new Phrase("Hi hats",0.0);


s.setTempo(variableE * 2);

// probability array double[] kickProbs = {variableA / 100.0, variableD / 100.0, variableD / 100.0, variableD / 100.0};
double[] snareProbs = {variableD / 100.0, variableD / 100.0,
variableB / 100.0, variableD / 100.0};
double[] hatProbs = {variableB / 100.0, variableC / 100.0,
variableB / 100.0, variableC / 100.0};
 
//create the phrase note by note double choice; for (int r = 0; r < 8; r++) { for(int i=0; i<kickProbs.length; i++){ choice = Math.random(); if(choice < kickProbs[i]) { Note n = new Note(C2, SEMI_QUAVER); kPhrase.addNote(n); } else { Note n = new Note(REST, SEMI_QUAVER); kPhrase.addNote(n); } } for(int i=0; i<snareProbs.length; i++){ choice = Math.random(); if(choice < snareProbs[i]) { Note n = new Note(D2, SEMI_QUAVER); sPhrase.addNote(n); } else { Note n = new Note(REST, SEMI_QUAVER); sPhrase.addNote(n); } } for(int i=0; i<hatProbs.length; i++){ choice = Math.random(); if(choice < hatProbs[i]) { Note n = new Note(FS2, SEMI_QUAVER); hPhrase.addNote(n); } else { Note n = new Note(REST, SEMI_QUAVER); hPhrase.addNote(n); } } } p.addPhrase(kPhrase); p.addPhrase(sPhrase); p.addPhrase(hPhrase); s.addPart(p); return s; } }



jMusic Tutorial Index


© 2001 Andrew Brown