JM-550 Drum Machine:
AWT List
This series of classes introduces a simple, but extendible, drum machine
program.
There are a series of tutorials about the jm-550 classes (influenced by
the drum patterns of the Boss DR-550 drum machine) which show the development
of a Java graphical user interface for a jMusic application.
The first tutorial looked at the application
without any GUI code, in the second tutorial
some simple start and stop buttons were displayed in a window frame. In
the third tutorial sliders were added to control tempo and
volume, and in this tutorial a list of drum patterns is added. So here
goes...
This tutorial introduces the AWT (Abstract
Windowing Toolkit) List class.
Here is the GUI generated by this program:
This tutorial concerns the class JM550d
Click here to view the source.
There are three other classes required for this tutorial,
the Basic_550 and EightBeat1 classes (download and compile
if you don't already have them from a previous
tutorial)
and the EightBeat1FillIn class, to provide
a second pattern class so you can hear the change when selecting one from
the list.
Lets have a closer look.
import jm.JMC; import jm.music.data.*; import jm.music.tools.*; import jm.util.*; import java.awt.*; import java.awt.event.*;
|
In order to use the AWT classes we need to
import two packages: java.awt.*; and java.awt.event.*; The
awt package has the classes for windows buttons and so on, and the awt.event
package has classes for handling mouse clicks on the buttons, movement
of the sliders, and so on.
public class JM550d extends Frame implements JMC, ActionListener, AdjustmentListener, ItemListener { private static Button start, stop; private static Scrollbar tempoSlider, volumeSlider; private static Label tempoValue, volumeValue; private static List patterns; private static Basic_550 pat; public static void main(String[] args) { new JM550d();
pat = new EightBeat1();
Play.midiCycle(pat.getScore());
} |
The new addition to the class declaration is the implementation of the
ItemListener interface.
This is the listener used by the awt List class. You should now see the
pattern of connection between GUI interface components and listener interfaces.
It is that different GUI components that can respond to user actions (using
mouse, keyboard, etc.) have associated listener interfaces that handle
actions upon them. For example, Buttons use the ActionListener, ScrollBars
use the AdjustmentListener, and Lists use the ItemListener.
To use a listener interface your class implements it in the class declaration
and you provide the associated method - in the case of the ItemListener
this is the itemStateChanged()
method - see below.
The main method here is identical to previous
incarnations of the JM550 class.
public JM550d() { super("JM-550 Drum Machine");
Panel transport = new Panel();
start = new Button("Play");
start.addActionListener(this);
transport.add(start);
stop = new Button("Stop");
stop.addActionListener(this);
transport.add(stop);
this.add(transport, "South");
Panel tempoPanel = new Panel();
tempoPanel.setLayout(new BorderLayout());
Label tempoLabel = new Label("Tempo", Label.CENTER);
tempoPanel.add(tempoLabel, "North");
tempoSlider = new Scrollbar( Scrollbar.VERTICAL, 250 - 130, 20, 0, 250); tempoSlider.addAdjustmentListener(this); tempoPanel.add("Center", tempoSlider); tempoValue = new Label("130", Label.CENTER); tempoPanel.add(tempoValue, "South"); this.add(tempoPanel, "West");
Panel volumePanel = new Panel();
volumePanel.setLayout(new BorderLayout());
Label volumeLabel = new Label("Volume", Label.CENTER);
volumePanel.add(volumeLabel, "North");
volumeSlider = new Scrollbar( Scrollbar.VERTICAL, 3, 1, 0, 10); volumeSlider.addAdjustmentListener(this); volumePanel.add("Center", volumeSlider); volumeValue = new Label("100", Label.CENTER); volumePanel.add(volumeValue, "South"); this.add(volumePanel, "East"); |
In the constructor all the GUI components are added. As these tutorials
have proceeded we have more and more code relating to the GUI.
Above is the code so far, repeated for your convenience, and below is
the new code for the List.
As you can see writing the GUI can be more complex, time consuming and
code dense than the actual workings of the jMusic composition.
patterns = new List(5);
patterns.addItemListener(this);
patterns.add("EightBeat1");
patterns.add("EightBeat1Fill");
patterns.select(0);
this.add(patterns, "Center");
this.setVisible(true);
} |
Adding the List component follows similar steps to the other GUI components.
First we declare a new List instance called patterns.
We register it with the ItemListener using its addItemListener() method.
The word 'this' passed to that method indicates that the place to look
for the associated itemStateChanged() method is in 'this' class.
We then add two items to the list, these are simply Strings (text names)
with which we will later associate the pattern instances.
These Strings will appear in out list - they should be human readable
and have sensible names.
Next we tell the List instance to start out with the zeroith item in the
list selected.
The List is added to the frame in the centre
area of its border layout.
Finally, the frame is made visible.
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == start) player.resumePlayback();
if (ae.getSource() == stop) player.suspendPlayback();
}
public void adjustmentValueChanged(AdjustmentEvent ae) {
if (ae.getSource() == tempoSlider) {
int value = 250 - tempoSlider.getValue();
tempoValue.setText(Integer.toString(value));
pat.setTempo(value);
}
if (ae.getSource() == volumeSlider) {
int value = 12 * (10 - volumeSlider.getValue());
volumeValue.setText(Integer.toString(value));
pat.setScoreVolume(value);
pat.changeDynamics();
}
} |
The methods for handling the button clicks
and scroll bar movements are shown above - details about these is covered
in previous tutorials.
public void itemStateChanged(ItemEvent ie) {
if (ie.getSource() == patterns) {
int selected = patterns.getSelectedIndex();
if (selected == 0) pat = new EightBeat1();
if (selected == 1) pat = new EightBeat1FillIn();
}
}
} |
The itemStateChanged() method is called each time the user selects and
item in the list.
When this occurs the listener passes an ItemEvent object containing all
the details of the action to this method. We first check to see that the
message is from the patterns List (of course there is no other list in
this class but we're being thorough).
If so, an integer variable called 'selected' is declared and given the
number of the selected list item (0, 1, 2, 3, ...). We have only two items
currently so the value will be 0, 1, or -1 if no item is selected.
We handle each case separately. If the value
is 0 then the first item was selected, the EightBeat1 pattern, and so
we set our classes current pattern, pat, to a new instance of the EightBeat1
class. Similarly if the list index is 1 we change to a new EightBeat1FillIn
object. Since this is the same reference the Play class is holding,
the next time it goes to play a bar (or measure) the new pattern will
be heard.
You might try making new drum pattern classes
and adding them to the list.
|