| 平台/系列 | 代表機型 | 支援 API | 特點 |
|---|---|---|---|
| S40 (早期) | 7210, 3300, 6230, 6600 | com.nokia.mid.sound.Sound (專有) | 僅支援音調序列 (Tone)、簡短音效、無 MIDI 流式播放 |
| S60 (早期) | 3650, 7650, 6600 | com.nokia.mid.sound.Sound (專有) | 同 S40,部分機型支援較長音調 |
| S40/S60 (後期) | 7610, 6280, N70, N95 | MMAPI (JSR 135) + 專有 API 並存 | 完整支援 MIDI、WAV、AMR、MP3 (視編解碼器) |
import com.nokia.mid.sound.Sound;
// 建構子
Sound(byte[] data, int format) // format: Sound.FORMAT_TONE
// 方法
void play(int loopCount) // loopCount=-1 循環
void stop()
void setGain(int level) // 0-255 音量
.mid)。public class NokiaSoundPlayer {
private Sound sound;
private static final byte[] EXPLOSION_TONE = {
(byte)0x02, (byte)0x4a, (byte)0x3a, (byte)0x40,
(byte)0x04, (byte)0x00, (byte)0x0b, (byte)0x28,
(byte)0x83, (byte)0x28, (byte)0x28, (byte)0xd2,
(byte)0x28, (byte)0x00
};
public void playExplosion() {
stop(); // 避免重疊
try {
sound = new Sound(EXPLOSION_TONE, Sound.FORMAT_TONE);
sound.setGain(200); // 音量
sound.play(1); // 播放一次
} catch (Exception e) {
// 靜默失敗,不影響遊戲主流程
}
}
public void stop() {
if (sound != null) {
sound.stop();
sound = null;
}
}
}
Devices/Nokia_XXXX/lib/class.zip (或 classes.zip)。com/nokia/mid/sound/Sound.class。lib/nokia-sound.jar,加入 Build Path。com/nokia/mid/sound/ 目錄 (避免與手機內建類衝突) → 重新打包 JAR → 更新 JAD 大小。import javax.microedition.media.*;
public class MmaPlayer {
private Player player;
public void playMidi(String resourcePath) { // e.g. "/audio/bgm.mid"
stop();
try {
InputStream is = getClass().getResourceAsStream(resourcePath);
if (is == null) throw new IllegalArgumentException("Resource not found: " + resourcePath);
player = Manager.createPlayer(is, "audio/midi");
player.addPlayerListener(this);
player.setLoopCount(1);
player.realize(); // 預載資源
player.prefetch(); // 緩衝數據
player.start(); // 開始播放
} catch (MediaException | IOException e) {
// 錯誤處理
}
}
public void playerUpdate(Player p, String event, Object data) {
if (PlayerListener.END_OF_MEDIA.equals(event)) {
closePlayer();
} else if (PlayerListener.ERROR.equals(event)) {
// 處理錯誤
}
}
public void stop() {
closePlayer();
}
private void closePlayer() {
if (player != null) {
try { player.close(); } catch (Exception ignored) {}
player = null;
}
}
}
J2ME 生命週期:來電/按紅鍵/切換應用 → MIDlet.pauseApp() 被調用。若不處理,Player 繼續播放消耗電量並干擾用戶。
public class GameMidlet extends MIDlet {
private GameCanvas gameCanvas; // 含音頻播放器
private boolean soundEnabled = true;
protected void pauseApp() {
if (gameCanvas != null && soundEnabled) {
gameCanvas.stopAllSounds(); // 停止 MMAPI Player / Nokia Sound
}
}
protected void startApp() {
if (gameCanvas != null && soundEnabled) {
gameCanvas.resumeSounds(); // 可選:恢復背景音樂
}
}
}
public class GameCanvas extends Canvas {
private MmaPlayer bgmPlayer;
private NokiaSoundPlayer sfxPlayer;
public void stopAllSounds() {
if (bgmPlayer != null) bgmPlayer.stop();
if (sfxPlayer != null) sfxPlayer.stop();
}
public void resumeSounds() {
// 可選:恢復 BGM
if (bgmPlayer != null) bgmPlayer.playMidi("/audio/bgm.mid");
}
}
public interface SoundPlayer {
void playEffect(String name);
void playMusic(String name);
void stopAll();
}
public class SoundManager {
private static SoundPlayer instance;
public static SoundPlayer getInstance() {
if (instance == null) {
// 檢測 MMAPI 可用性
boolean hasMMAPI = false;
try {
Class.forName("javax.microedition.media.Manager");
hasMMAPI = true;
} catch (ClassNotFoundException ignored) {}
String platform = System.getProperty("microedition.platform").toLowerCase();
boolean isNokia = platform.contains("nokia");
if (hasMMAPI) {
instance = new MmaSoundPlayer(); // 完整功能
} else if (isNokia) {
instance = new NokiaSoundPlayerAdapter(); // 僅音效
} else {
instance = new NullSoundPlayer(); // 靜默實作
}
}
return instance;
}
}
setLoopCount(-1)。pauseApp() 停止所有 Player,destroyApp() 釋放資源。