首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME MMAPI 遊戲音效開發:從 JAR 讀取 WAV 播放完整指南

     編輯:J2ME

前言:讓 MIDlet 聽見聲音

Mobile Media API (MMAPI, JSR 135) 是 MIDP 2.0 標配、MIDP 1.0 可選包,提供統一的 Manager.createPlayer() 工廠方法播放音頻/視頻。本文聚焦遊戲常見場景:從 JAR 內部讀取 WAV 文件並播放,覆蓋流獲取、Player 生命週期、循環控制、異常處理。

一、 支持格式與設備差異

格式MIME 類型典型支持備註
WAVaudio/x-wav幾乎所有設備無壓縮、體積大、延遲極低,適合短音效
MIDI / SP-MIDIaudio/midi廣泛支持體積小、適合背景音樂
AMRaudio/amr部分 3G 設備語音編碼,適合錄音回放
MP3 / AACaudio/mpeg高端/智能機需授權解碼器,MIDP 2.0 不強制

實戰建議:音效用 8kHz/16bit 單聲道 WAV(< 20KB/個),背景音樂用 SP-MIDI,發布前用 Manager.getSupportedContentTypes(null) 探測目標設備支持列表。

二、 核心三步驟代碼模板

// 1. 獲取輸入流 (從 JAR 根目錄 /res 下讀取)
InputStream is = getClass().getResourceAsStream("/res/click.wav");
// 注意:路徑以 '/' 開頭表示 JAR 根,區分大小寫

// 2. 創建 Player
Player player = Manager.createPlayer(is, "audio/x-wav"); // MIME 必須準確

// 3. 實現並啟動
player.realize();   // 預加載解碼器、分配資源(可選,start() 會隱式調用)
player.prefetch();  // 緩衝數據(可選)
player.start();     // 開始播放

三、 完整 MIDlet 示例

package sound;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import java.io.*;

public class SoundMIDlet extends MIDlet {
    private Player player;

    public SoundMIDlet() {
        try {
            InputStream is = getClass().getResourceAsStream("/Autorun.wav");
            player = Manager.createPlayer(is, "audio/x-wav");
        } catch (IOException e) { System.err.println("IO: " + e); }
          catch (MediaException e) { System.err.println("Media: " + e); }
    }

    protected void startApp() {
        if (player != null) {
            try { player.start(); }
            catch (MediaException e) { System.err.println("Start: " + e); }
        }
    }

    protected void pauseApp() {
        if (player != null) player.stop(); // 釋放音頻設備
    }

    protected void destroyApp(boolean unconditional) {
        if (player != null) {
            player.close(); // 徹底釋放資源
            player = null;
        }
    }
}

四、 進階控制:循環、音量、播放進度

需求API示例
循環播放 N 次player.setLoopCount(n)player.setLoopCount(3); (0=無限)
設置音量 0-100VolumeControl vc = (VolumeControl) player.getControl("VolumeControl"); vc.setLevel(50);部分設備不支持,需 if (vc!=null) 守衛
獲取/設置播放時間player.getMediaTime() (微秒)、player.setMediaTime(us)精確同步歌詞/動畫
監聽播放結束player.addPlayerListener(new PlayerListener() { public void playerUpdate(Player p, String event, Object o) { if (PlayerListener.END_OF_MEDIA.equals(event)) { /* 下一首 */ } } });實現播放列表

五、 避坑指南

  1. 流讀取失敗返回 null:路徑大小寫不匹配、文件未打包進 JAR(檢查 WTK 的 res 目錄)、文件名含中文/空格導致 URL 編碼問題。
  2. MediaException: Unsupported content type:MIME 類型寫錯(如 audio/wav 錯,正確 audio/x-wav)、設備確實不支持該格式。
  3. 播放無聲音:player.realize() 拋異常被吞沒、設備靜音模式、音量控制為 0、並發播放超過設備最大聲道數(通常 1-2)。
  4. 內存洩漏:destroyApp() 必須 player.close(),否則本地解碼器資源不釋放,導致後續創建 Player 失敗。
  5. 線程安全:Player 方法線程安全,但 start() 可能阻塞(緩衝),建議在非 UI 線程調用或預先 prefetch()。

六、 最佳實踐:音效管理器單例

public class SoundManager {
    private static SoundManager instance = new SoundManager();
    private Hashtable players = new Hashtable(); // key: name, value: Player

    private SoundManager() {}

    public static SoundManager getInstance() { return instance; }

    public void load(String name, String mime) {
        try {
            InputStream is = getClass().getResourceAsStream("/res/" + name);
            Player p = Manager.createPlayer(is, mime);
            p.realize(); p.prefetch();
            players.put(name, p);
        } catch (Exception e) { System.err.println("Load " + name + ": " + e); }
    }

    public void play(String name, int loopCount) {
        Player p = (Player) players.get(name);
        if (p != null) {
            try { p.setLoopCount(loopCount); p.setMediaTime(0); p.start(); }
            catch (MediaException e) { System.err.println("Play " + name + ": " + e); }
        }
    }

    public void stopAll() {
        Enumeration e = players.elements();
        while (e.hasMoreElements()) {
            Player p = (Player) e.nextElement();
            p.stop(); p.close();
        }
        players.clear();
    }
}

// 使用:
// SoundManager.getInstance().load("jump.wav", "audio/x-wav");
// SoundManager.getInstance().play("jump.wav", 1);

七、 總結

MMAPI 以工廠模式屏蔽了平台差異,「流 → Player → start」三步走極簡。遊戲開發中,建議啟動時預載所有音效至 SoundManager,運行時零延遲播放;pauseApp() 停止、destroyApp() 關閉,做個內存友好的良民應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved