You can play tones by calling this method in javax.microedition.media.Manager:
public static void playTone(int note, int duration, int volume)
In this method, note is specified just like a MIDI note, where each integer corresponds to a single key on a piano keyboard. Middle C is 60, and the A above middle C (a 440 Hz tone) is 69. The duration is in milliseconds, and volume can range from 0, silent, to 100, loudest.
Like most other methods in the ABB, playTone() may throw a MediaException. Although support for simple tones is required by the specification, the device may be temporarily unable to play tones. (For example, a mobile phone might be using the tone generation hardware to ring the phone.)
Figure 12-1 shows PianoCanvas, an example that displays a simple piano keyboard and allows the user to navigate through the keys to play different tones. PianoCanvas is presented in Listing 12-1. The code for playing the tones is very compact, consisting solely of a call to playTone() in the keyPressed() method. The rest of the code is devoted to the user interface.
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
public class PianoCanvas
extends Canvas {
private static final int[] kNoteX = {
0, 11, 16, 29, 32, 48, 59, 64, 76, 80, 93, 96
};
private static final int[] kNoteWidth = {
16, 8, 16, 8, 16, 16, 8, 16, 8, 16, 8, 16
};
private static final int[] kNoteHeight = {
96, 64, 96, 64, 96, 96, 64, 96, 64, 96, 64, 96
};
private static final boolean[] kBlack = {
false, true, false, true, false,
false, true, false, true, false, true, false
};
private int mMiddleCX, mMiddleCY;
private int mCurrentNote;
public PianoCanvas() {
int w = getWidth();
int h = getHeight();
int fullWidth = kNoteWidth[0] * 8;
mMiddleCX = (w - fullWidth) / 2;
mMiddleCY = (h - kNoteHeight[0]) / 2;
mCurrentNote = 60;
}
public void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
g.setColor(0xffffff);
g.fillRect(0, 0, w, h);
g.setColor(0x000000);
for (int i = 60; i <= 72; i++)
drawNote(g, i);
drawSelection(g, mCurrentNote);
}
private void drawNote(Graphics g, int note) {
int n = note % 12;
int octaveOffset = ((note - n) / 12 - 5) * 7 * kNoteWidth[0];
int x = mMiddleCX + octaveOffset + kNoteX[n];
int y = mMiddleCY;
int w = kNoteWidth[n];
int h = kNoteHeight[n];
if (isBlack(n))
g.fillRect(x, y, w, h);
else
g.drawRect(x, y, w, h);
}
private void drawSelection(Graphics g, int note) {
int n = note % 12;
int octaveOffset = ((note - n) / 12 - 5) * 7 * kNoteWidth[0];
int x = mMiddleCX + octaveOffset + kNoteX[n];
int y = mMiddleCY;
int w = kNoteWidth[n];
int h = kNoteHeight[n];
int sw = 6;
int sx = x + (w - sw) / 2;
int sy = y + h - 8;
g.setColor(0xffffff);
g.fillRect(sx, sy, sw, sw);
g.setColor(0x000000);
g.drawRect(sx, sy, sw, sw);
g.drawLine(sx, sy, sx + sw, sy + sw);
g.drawLine(sx, sy + sw, sx + sw, sy);
}
private boolean isBlack(int note) {
return kBlack[note];
}
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case LEFT:
mCurrentNote--;
if (mCurrentNote < 60)
mCurrentNote = 60;
repaint();
break;
case RIGHT:
mCurrentNote++;
if (mCurrentNote > 72)
mCurrentNote = 72;
repaint();
break;
case FIRE:
try { Manager.playTone(mCurrentNote, 1000, 100); }
catch (MediaException me) {}
break;
default:
break;
}
}
}
The ABB also offers support for playing sampled audio files, although the specification does not require support for this feature. To play sampled audio, you just need to get a Player for the data you wish to hear, then start the Player running. You can get a Player by asking Manager for one. In its simplest form, playing sampled audio data looks like this:
URL url = "http://65.215.221.148:8080/wj2/res/relax.wav"; Player p = Manager.createPlayer(url); p.start();
In this approach, the web server provides the content type of the data. Another approach is to obtain an InputStream to the audio data, then create a Player by telling Manager the content type of the data. This is handy for reading audio files that are stored as resources in the MIDlet suite JAR. For example:
InputStream in = getClass().getResourceAsStream("/relax.wav");
Player player = Manager.createPlayer(in, "audio/x-wav");
player.start();
Listing 12-2 is a simple MIDlet that demonstrates both techniques.
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.media.*;
public class AudioMIDlet
extends MIDlet
implements CommandListener, Runnable {
private Display mDisplay;
private List mMainScreen;
public void startApp() {
mDisplay = Display.getDisplay(this);
if (mMainScreen == null) {
mMainScreen = new List("AudioMIDlet", List.IMPLICIT);
mMainScreen.append("Via HTTP", null);
mMainScreen.append("From resource", null);
mMainScreen.addCommand(new Command("Exit", Command.EXIT, 0));
mMainScreen.addCommand(new Command("Play", Command.SCREEN, 0));
mMainScreen.setCommandListener(this);
}
mDisplay.setCurrent(mMainScreen);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) notifyDestroyed();
else {
Form waitForm = new Form("Loading...");
mDisplay.setCurrent(waitForm);
Thread t = new Thread(this);
t.start();
}
}
public void run() {
String selection = mMainScreen.getString(
mMainScreen.getSelectedIndex());
boolean viaHttp = selection.equals("Via HTTP");
if (viaHttp)
playViaHttp();
else
playFromResource();
}
private void playViaHttp() {
try {
String url = getAppProperty("AudioMIDlet-URL");
Player player = Manager.createPlayer(url);
player.start();
}
catch (Exception e) {
showException(e);
return;
}
mDisplay.setCurrent(mMainScreen);
}
private void playFromResource() {
try {
InputStream in = getClass().getResourceAsStream("/relax.wav");
Player player = Manager.createPlayer(in, "audio/x-wav");
player.start();
}
catch (Exception e) {
showException(e);
return;
}
mDisplay.setCurrent(mMainScreen);
}
private void showException(Exception e) {
Alert a = new Alert("Exception", e.toString(), null, null);
a.setTimeout(Alert.FOREVER);
mDisplay.setCurrent(a, mMainScreen);
}
}