ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Java and Sound, Part 2
Pages: 1, 2

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( );
                }
            });
    }
}

Exercises

If you want to delve deeper into the Java Sound API, read the JavaSound Programmer's Guide included with the Java SDK documentation bundle. Also visit the jsresources.org web site for a useful FAQ and many more example programs. When working with MIDI programs, you may need information from the MIDI specification. Unfortunately, this spec is not available online. It can be ordered in printed form from the official midi.org web site, but you can often find the information you need by searching the Web.

These exercises will start you on your way to JavaSound fun:

  • Exercise 17-1. Convert the Drums program so that it runs as an applet within a web browser.

  • Exercise 17-2. Modify the PlayerPiano program to play percussion instead of piano notes. Define your own grammar for percussive scores, and have the program play your percussion Sequence repeatedly, creating a rhythm track.

  • Exercise 17-3. Read up on the details of the PCM audio format, and then implement an AudioInputStream subclass that synthesizes audio data (such as a pure sine wave) in this format. (This is an advanced exercise.)

David Flanagan is the author of a number of O'Reilly books, including Java in a Nutshell, Java Examples in a Nutshell, Java Foundation Classes in a Nutshell, JavaScript: The Definitive Guide, and JavaScript Pocket Reference.


Return to ONJava.com.