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: |
|
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
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(); for(int i=0;i<12;){ int pitch = C4+(int)(Math.random() * variableA + 1) - variableA / 2; if (pitch>=0&&pitch<=127){ Note n = new Note(pitch, DEMI_SEMI_QUAVER * (int)(Math.random()*variableB + 1)); scale.addNote(n); i++; } }
p.addPhrase(scale);
s.addPart(p);
Instrument sine = new SineInst(44100);
Instrument[] instArray = {sine};
insts = instArray;
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;
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);
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};
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;
}
}
|
|