Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Java SE 综合讨论区  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 Use java to PRODUCE MIDI SOUND example..
terrence3321



Jute User


发贴: 40
积分: 50
于 2003-08-05 14:58 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Just found this, for those interested in java MIDI can look here...

Adding audio cues to your Java desktop application can give it
more of a polished feel and can dramatically improve usability.
The Musical Instrument Digital Interface (MIDI) is a
communication protocol for passing musical events between
devices. A MIDI file contains audio commands rather than actual
audio. Audio is a digital representation of sound, while MIDI
represents the commands to a sound engine to recreate the sound.
In this tech tip, you'll learn three ways to generate MIDI sound
to augment your J2SE applications. Each of these techniques uses
the javax.sound.midi package which has been part of the Java
platform since J2SE 1.3.

In the first technique, you generate a sound by making a direct
call to a MidiChannel object. This object represent a single MIDI
channel, that is, a single channel for MIDI transmission. To
start a note playing through the channel, you use the noteOn()
method of the MidiChannel object. To stop a note playing, you use
the noteOff() method.

The noteOn() method requires two ints. The first indicates the
note being played. In the following program, SingleNoteChannel,
the int 60 passed to the noteOn() method is the standard MIDI
note number for middle C. An integer up or down corresponds to
a half step. Twelve half steps comprise an octave.

The second parameter for the noteOn() method indicates the speed
with which the key is struck. Although this parameter is often
referred to as the velocity, you can think of it as a volume
control. In the SingleNoteChannel program, the second parameter
passed to the noteOn() method is 70. After you run
SingleNoteChannel, experiment with other speeds by changing 70
to other numbers.

There are two signatures of the noteOff() method. One takes the
same two parameters taken by noteOn(), and the other requires the
number corresponding to the note being played.

Before you can play a note, there is a certain amount of setup to
be done. This is demonstrated in the SingleNoteChannel
constructor. In order to generate sound, you need a Synthesizer
object. This object represents a collection of MidiChannels,
usually one for each of the 16 channels prescribed by the MIDI
1.0 specification. The SingleNoteChannel constructor gets a handle
to a Synthesizer using a factory method in the MidiSystem class.
The constructor then calls the Synthesizer's open() method, and
gets an array of the available MidiChannels by calling the
getChannels() method. It then selects the first MidiChannel at
index 0.

import javax.sound.midi.MidiChannel;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;

public class SingleNoteChannel {

private MidiChannel channel;

public SingleNoteChannel() {
try {
Synthesizer synth =
MidiSystem.getSynthesizer();
synth.open();
channel = synth.getChannels()[0];
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}

public void playNote(int note) {
channel.noteOn(note, 70);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
channel.noteOff(note, 70);
}

public static void main(String[] args) {
new SingleNoteChannel().playNote(60);
}
}

The playNote() method in the SingleNoteChannel program starts
playing a note with a call to the MidiChannel noteOn() method.
The note continues to play while the thread sleeps for one
second. Then a call to the MidiChannel noteOff() method ends the
playing of the note.

You could use this first technique to associate certain notes
with the pressing and releasing of buttons, keys, or other
on-screen events.

Now let's look at a second technique to generate MIDI sound.
In this approach, you use a Receiver object associated with
a Synthesizer. Instead of getting a specific MidiChannel for a
Synthesizer, you get a handle to a Receiver. You create MIDI
messages of type ShortMessage, customize them, and then play
them by calling the send() method of the Receiver object.

A ShortMessage object contains a MIDI message that has at most
two data bytes. You use the setMessage() method to set the
parameters of the MIDI message or to set message parameters for
a channel message (this depends on the signature of the method)
In the program below, SingleNoteSynthesizer, the signature of the
setMessage() method sets message parameters for a channel message.
This signature takes four ints. The first indicates the command
being sent. The choices are NOTE_ON and NOTE_OFF. The second int
identifies the target channel. To be consistent with the previous
example, this parameter specifies index 0. For the NOTE_ON and
NOTE_OFF commands the last two ints are the note identifier and
velocity. In SingleNoteSynthesizer they are the same ints that
were passed into the noteOn() and noteOff() methods in the
SingleNoteChannel example.

import javax.sound.midi.ShortMessage;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;

public class SingleNoteSynthesizer {

private ShortMessage message =
new ShortMessage();
private Receiver receiver;

private SingleNoteSynthesizer() {
try {
Synthesizer synth =
MidiSystem.getSynthesizer();
synth.open();
receiver = synth.getReceiver();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}

public void playNote(int note) {
setShortMessage(note, ShortMessage.NOTE_ON);
receiver.send(message, -1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setShortMessage(note, ShortMessage.NOTE_OFF);
receiver.send(message, -1);
}

private void setShortMessage(
int note, int onOrOff) {
try {
message.setMessage(onOrOff, 0, note, 70);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
new SingleNoteSynthesizer().playNote(60);
}
}

So far you've seen examples that play a single note. One thing
you might not have realized is that the examples played the note
on a default instrument. But what about playing a note on a
different instrument? In this third technique for generating MIDI
sound you'll see how to do this. Let's start by examining what's
available. Here's a method that generates a list of available
instruments:

public void listAvailableInstruments(){
Instrument[] instrument =
synth.getAvailableInstruments();
for (int i=0; i<instrument.length; i++){
System.out.println(i + " "
+ instrument[i].getName());
}
}

If you call the method, you get a list whose first items look
like this:

0 Piano
1 Bright Piano
2 Electric Grand
3 Honky Tonk Piano
4 Electric Piano 1
5 Electric Piano 2
6 Harpsichord
7 Clavinet
8 Celesta
9 Glockenspiel
10 Music Box
11 Vibraphone
12 Marimba
13 Xylophone
14 Tubular Bell
15 Dulcimer
16 Hammond Organ
17 Perc Organ
18 Rock Organ
19 Church Organ
20 Reed Organ
21 Accordion
22 Harmonica
23 Tango Accordion
24 Nylon Str Guitar
25 Steel String Guitar
26 Jazz Electric Gtr
27 Clean Guitar
28 Muted Guitar
29 Overdrive Guitar
30 Distortion Guitar

To illustrate the approach, let's enhance SingleNoteSynthesizer
to play more than one note at a time using different instruments.
If you examine the enhanced program, SingleNoteSynthesizer2, you
will notice that the program still sleeps a Thread to measure
time. This is really not robust enough for creating and playing
music. In addition, if done in the AWT Event Dispatch thread,
this will prevent your GUI from processing events or repainting.
These issues will be addressed later in the tip using the final
technique for generating MIDI sound.

As demonstrated in SingleNoteSynthesizer2, you change the
instrument being played by calling the programChange() method in
MidiChannel. You pass the method an int that corresponds to the
instrument you want from the list you generated above. In this
example, the int is 19, corresponding to a church organ.

Notice too that the code has also been refactored so that
startNote() creates a message with the NOTE_ON command, and
stopNote() creates one with the NOTE_OFF command. The playNote()
method calls startNote(), sleeps for the number of milliseconds
passed in as the duration, and then calls stopNote().

import javax.sound.midi.ShortMessage;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Receiver;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.InvalidMidiDataException;

public class SingleNoteSynthesizer2 {
private ShortMessage message = new ShortMessage();
private Synthesizer synth;
private Receiver receiver;

public SingleNoteSynthesizer2() {
try {
synth = MidiSystem.getSynthesizer();
synth.open();
receiver = synth.getReceiver();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}

public void startNote(int note) {
setShortMessage(ShortMessage.NOTE_ON, note);
receiver.send(message, -1);
}

public void stopNote(int note) {
setShortMessage(ShortMessage.NOTE_OFF, note);
receiver.send(message, -1);
}

public void playNote(int note, int duration){
startNote(note);
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopNote(note);
}

public void setInstrument(int instrument){
synth.getChannels()[0].programChange(
instrument);
}

private void setShortMessage(
int onOrOff, int note) {
try {
message.setMessage(onOrOff, 0, note, 70);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}

public void playMajorChord(int baseNote){
playNote(baseNote,1000);
playNote(baseNote+4,1000);
playNote(baseNote+7, 1000);
startNote(baseNote);
startNote(baseNote+4);
playNote(baseNote+7,2000);
stopNote(baseNote+4);
stopNote(baseNote);
}

public static void main(String[] args) {
SingleNoteSynthesizer2 synth
= new SingleNoteSynthesizer2();
synth.setInstrument(19);
synth.playMajorChord(60);
}
}

A major chord is constructed from a base note, the note four half
steps above it, and the note three half spaces above that. In
SingleNoteSynthesizer2, the playMajorChord() method first plays
these notes, one at a time, and then plays them all at once. The
timing is done using Threads. This is not the recommended approach
when timing is important. In that case you should use a Sequencer.

A Sequencer object includes methods that give you more control
(as compared to the previous approach) over the timing of MIDI
events. As before, use a factory method from MidiSystem. This
time obtain and open a Sequencer. This is shown in the next
example, SequencerSound. Comparing this example to the preceding
examples, you should notice some notable changes to the code.
First the startNote() and stopNote() methods take an int that
represents the point in time at which the message being created
takes place. The createTrack() method creates a Sequence with four
ticks for each quarter note. You can think of ticks as
subdivisions. In other words, a measure of music in 4/4 time has
four quarter notes or sixteen ticks.

The setShortMessage() method calls setMessage(), as before.
Then the program creates a MidiEvent object based on this
ShortMessage and associated with a specific tick. Finally the
program adds a MidiEvent to the Track. To play the track, the
startSequencer() method assigns the newly created Sequence to the
Sequencer. The playback begins with a call to the start() method,
and the tempo is set to sixty beats per minute (BPM) using the
setTempoInBPM() method.

import javax.sound.midi.Track;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Sequence;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.MidiEvent;

public class SequencerSound {
private Track track;
private Sequencer sequencer;
private Sequence sequence;

public SequencerSound() {
try {
sequencer = MidiSystem.getSequencer();
sequencer.open();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
createTrack();
makeScale(20);
startSequencer();
}

private void startSequencer() {
try {
sequencer.setSequence(sequence);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
sequencer.start();
sequencer.setTempoInBPM(60);
}

private void createTrack() {
try {
sequence = new Sequence(Sequence.PPQ, 4);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
track = sequence.createTrack();
}

public void startNote(int note, int tick) {
setShortMessage(
ShortMessage.NOTE_ON, note, tick);
}

public void stopNote(int note, int tick) {
setShortMessage(
ShortMessage.NOTE_OFF, note, tick);
}

private void setShortMessage(
int onOrOff, int note, int tick) {
ShortMessage message = new ShortMessage();
try {
message.setMessage(onOrOff, 0, note, 90);
MidiEvent event = new MidiEvent(
message, tick);
track.add(event);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}

public void makeScale(int baseNote) {
for (int i = 0; i < 13; i++) {
startNote(baseNote + i, i);
stopNote(baseNote + i, i + 1);
startNote(baseNote + i, 25 - i);
stopNote(baseNote + i, 26 - i);
}
}

public static void main(String[] args) {
new SequencerSound();
}
}

This tip showed you how to produce and play back MIDI files. As a
developer, you are able to hear the music because a soundbank is
automatically installed along with the J2SE SDK. A soundbank
represents a set of instruments, and is needed to synthesize
sound. (There's a lot more to the soundbank concept, and it will
be covered in a later tip.) Non-developers might have to install
a soundbank separately to hear what you have created. When
installing a JRE for J2SE 1.4.1 or later, users have to opt-in to
include the soundbank in the installation.

For more information on saving and playing back MIDI files,
consult the documentation for javax.sound.midi
(http://java.sun.com/j2se/1.4.2/docs/api/javax/sound/midi/package-summary.html).
You'll find more information on the Java Sound API home page
(http://java.sun.com/products/java-media/sound/).




话题树型展开
人气 标题 作者 字数 发贴时间
2666 Use java to PRODUCE MIDI SOUND example.. terrence3321 16443 2003-08-05 14:58

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923