[ Team LiB ] Previous Section Next Section

17.7 Real-Time MIDI Sounds

Example 17-5 played a Sequence of MIDI events through a Sequencer object. It is also possible to synthesize music by directly controlling one or more MidiChannel objects of a Synthesizer object. This technique requires you to turn notes on and off in real time; it is demonstrated in Example 17-6, which turns your computer keyboard into a drum machine. This program uses MIDI channel 10, which is reserved (by the General Midi specification) for percussion. When sending notes to this channel, the different key numbers don't produce a different pitch, but instead make different percussive sounds. The Drums program displays an AWT window that is used to capture java.awt.event.KeyEvent objects. Key down and key up events are translated into noteOn and noteOff calls to the MidiChannel, using the keycode of the key as the number of the percussion instrument to play. The MIDI standard defines percussion instruments for notes 35 through 81, inclusive. You can examine the VK_ constants of KeyEvent to determine which keys produce which codes, or you can just experiment by striking keys at random!

Note that the program also uses the position of the mouse to control the volume of the percussion sounds. Move the mouse to the right side of the window for louder sounds, and move it to the left for softer sounds. If you don't hear anything, be sure that it is correctly positioned in the right side of the displayed window.

You may notice a slight delay between the time you strike a key and the time you hear a sound. This latency is inevitable with software synthesizers. The getLatency( ) method of the Synthesizer object is supposed to return the worst-case latency in microseconds.

Example 17-6. Drums.java
package je3.sound;
import javax.sound.midi.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * This program the MIDI percussion channel with a Swing window.  It monitors
 * keystrokes and mouse motion in the window and uses them to create music.
 * Keycodes between 35 and 81, inclusive, generate different percussive sounds.
 * See the VK_ constants in java.awt.event.KeyEvent, or just experiment.
 * Mouse position controls volume: move the mouse to the right of the window
 * to increase the volume.
 */
public class Drums extends JFrame {
    MidiChannel channel;  // The channel we play on: 10 is for percussion
    int velocity = 64;    // Default volume is 50%

    public static void main(String[  ] args) throws MidiUnavailableException
    {
        // We don't need a Sequencer in this example, since we send MIDI
        // events directly to the Synthesizer instead.
        Synthesizer synthesizer = MidiSystem.getSynthesizer( );
        synthesizer.open( );
        JFrame frame = new Drums(synthesizer);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(50, 128);  // We use window width as volume control
        frame.setVisible(true);
    }    

    public Drums(Synthesizer synth) {
        super("Drums");

        // Channel 10 is the GeneralMidi percussion channel.  In Java code, we
        // number channels from 0 and use channel 9 instead.
        channel = synth.getChannels( )[9];

        addKeyListener(new KeyAdapter( ) {
                public void keyPressed(KeyEvent e) {
                    int key = e.getKeyCode( );
                    if (key >= 35 && key <= 81) {
                        channel.noteOn(key, velocity);
                    }
                }
                public void keyReleased(KeyEvent e) {
                    int key = e.getKeyCode( );
                    if (key >= 35 && key <= 81) channel.noteOff(key);
                }
            });

        addMouseMotionListener(new MouseMotionAdapter( ) {
                public void mouseMoved(MouseEvent e) {
                    velocity = e.getX( );
                }
            });
    }
}
    [ Team LiB ] Previous Section Next Section