實例解析應用Java完成根本的音頻播放器的編寫要點。本站提示廣大學習愛好者:(實例解析應用Java完成根本的音頻播放器的編寫要點)文章只能為提供參考,不一定能成為您想要的結果。以下是實例解析應用Java完成根本的音頻播放器的編寫要點正文
Java音頻播放,由於必需依附到當地情況,所以JAVA在音頻處置方面優勢不年夜,或許說打從Java系統開辟時就沒太多的斟酌音頻播放身分,要曉得最早的Java 1.1版本中,沒有後來的javax.sound包,音頻只能經由過程Applet包調取……
遺憾的是,在圖形法式開辟中,我們的法式卻又不免要應用到配景音樂、後果音等合營圖象操作,哎,這其實是Sun年夜神給我們開的一個不打不小的打趣。萬幸後來Sun年夜神開眼,供給了javax.sound包,才挽救我們於水火倒懸傍邊~
然則繼之而來的成績是,在javax.sound包的應用中,好像Java多媒體對象類的通病般,並沒有供給非常完美的釋放機制。假如我們做Windows 開辟,挪用MediaPlayer重復N次能夠沒也甚麼年夜礙,但在Java中,假如音頻法式重復運轉的話,極輕易湧現內存累計消耗的情形,以致於最初拋出一個java.lang.OutOfMemoryError,然後……法式就掛了,用戶就傻了,我們就瘋了……
這曾經是“是可忍孰弗成忍 ”的成績了,有鑒於此,所以在自己的Loonframework框架開辟中,二次整合了sound下的相干辦法,力圖以最簡略的代碼,做出最完美的音頻掌握類。在Loonframework-game還沒有年夜成的如今,先摘錄一部門辦法,以供列位看官——拍磚!
對應收集資本挪用,在Loonframework中樹立了本身的uri用類,根本內容以下:
(個中StreamHelper為Loonframework本身的流媒體掌握類,getHttpStream辦法請自行調換。)
package org.loon.framework.game.net;
import org.loon.framework.game.helper.StreamHelper;
/** *//**
* <p>
* Title: LoonFramework
* </p>
* <p>
* Description:Loonframework公用uri(同一資本標識符)
* </p>
* <p>
* Copyright: Copyright (c) 2007
* </p>
* <p>
* Company: LoonFramework
* </p>
*
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/
public class URI ...{
//傳輸協定類型
public static final int _L_URI_HTTP = 1;
public static final int _L_URI_UDP = 2;
private String _uri;
private int _type;
/** *//**
* 析構函數,用於注入uri和type
*
* @param uri
* @param type
*/
public URI(String uri, int type) ...{
_uri = new String(uri);
_type = type;
}
/** *//**
* 析構函數,用於注入uri
*
* @param uri
*/
public URI(String uri) ...{
_uri = new String(uri);
_type = URI._L_URI_HTTP;
}
/** *//**
* 前往uri地點地位資本的byte數組。
*
* @return
*/
public byte[] getData() ...{
if (_uri == null) ...{
return null;
}
return StreamHelper.getHttpStream(_uri);
}
public String getURI() ...{
return _uri;
}
public int getType() ...{
return _type;
}
}
在Loonframework框架中,定制了一個基本的SoundData類,用以同一治理音頻數據源。
package org.loon.framework.game.sound;
import org.loon.framework.game.helper.StreamHelper;
import org.loon.framework.game.net.URI;
/** *//**
* <p>
* Title: LoonFramework
* </p>
* <p>
* Description:用以取得並緩存聲響文件數據(更進一步內容操作請見Loonframework-game框架)
* </p>
* <p>
* Copyright: Copyright (c) 2007
* </p>
* <p>
* Company: LoonFramework
* </p>
*
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/
public class SoundData ...{
private byte[] _data;
private boolean _loop;
private int _type;
public static final int _L_SOUNDTYPE_MIDI = 1;
public static final int _L_SOUNDTYPE_WAV = 2;
/** *//**
* 析構函數,用以注入uri,type,loop
*
* @param uri
* @param type
* @param loop
*/
public SoundData(URI uri, int type, boolean loop) ...{
if (uri != null) ...{
_data = uri.getData();
}
_type = type;
_loop = loop;
}
/** *//**
* 析構函數,用以注入data,type,loop
*
* @param data
* @param type
* @param loop
*/
public SoundData(byte[] data, int type, boolean loop) ...{
if (data != null && data.length > 0) ...{
_data = new byte[data.length];
// 直接copy byte數組
System.arraycopy(data, 0, _data, 0, _data.length);
}
_type = type;
_loop = loop;
}
/** *//**
* 析構函數,用以注入限制地位的resName,type,loop
* @param resName
* @param type
* @param loop
*/
public SoundData(String resName, int type, boolean loop) ...{
this(StreamHelper.GetDataSource(resName),type,loop);
}
public byte[] getData() ...{
return _data;
}
public boolean getLoop() ...{
return _loop;
}
public void setLoop(boolean loop) ...{
_loop = loop;
}
public int getType() ...{
return _type;
}
}
Loonframework將音頻播放相干辦法,封裝與SoundPlay當中,法式員可以不用理睬javax.sound外部細節,而直接挪用SoundPlay完成相干操作。
package org.loon.framework.game.sound;
import java.io.ByteArrayInputStream;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import org.loon.framework.game.net.URI;
/** *//**
* <p>
* Title: LoonFramework
* </p>
* <p>
* Description:用以停止聲響文件操作(僅為Loonframework中部門辦法,更具體請拜見Loonframework-game框架)
* </p>
* <p>
* Copyright: Copyright (c) 2007
* </p>
* <p>
* Company: LoonFramework
* </p>
*
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/
public class SoundPlay implements MetaEventListener, Runnable ...{
private int _sleepTime;
private Clip _audio;
private Sequencer _midi;
private boolean _loop;
private int _soundType;
private boolean _playing;
private Thread _thread = null;
private boolean _isRun = false;
/** *//**
* 析構函數,初始化SoundPlay
*
*/
public SoundPlay() ...{
_loop = false;
_soundType = 0;
_sleepTime = 1000;
_playing = false;
}
// 載入聲響文件
public boolean load(SoundData data) ...{
reset();
if (data == null || data.getData() == null) ...{
return false;
}
return init(data.getData(), data.getType(), data.getLoop());
}
/** *//**
* 直接播放url文件
*
* @param uri
* @param ftype
* @param loop
* @return
*/
public boolean load(URI uri, int ftype, boolean loop) ...{
// 刷新數據
reset();
if (uri == null) ...{
return false;
}
// 取得SoundData
SoundData data = new SoundData(uri, ftype, loop);
if (data == null || data.getData() == null) ...{
return false;
}
return init(data.getData(), data.getType(), data.getLoop());
}
/** *//**
* 初始化sound相干數據
*
* @param data
* @param ftype
* @param loop
* @return
*/
private boolean init(byte[] data, int ftype, boolean loop) ...{
boolean result = false;
ByteArrayInputStream bis = null;
try ...{
bis = new ByteArrayInputStream(data);
} catch (Exception e) ...{
bis = null;
}
if (bis == null) ...{
return false;
}
// 斷定類型
switch (ftype) ...{
// MIDI
case SoundData._L_SOUNDTYPE_MIDI:
// 當MIDI不存在時
if (_midi == null) ...{
try ...{
// 取得Sequencer
_midi = MidiSystem.getSequencer();
_midi.open();
} catch (Exception ex) ...{
_midi = null;
}
if (_midi != null) ...{
_midi.addMetaEventListener(this);
}
}
// 當MIDI照舊未取得時
if (_midi != null) ...{
// 從新創立Sequence
Sequence sc = null;
try ...{
sc = MidiSystem.getSequence(bis);
} catch (Exception e) ...{
sc = null;
}
if (sc != null) ...{
try ...{
_midi.setSequence(sc);
// 取得能否輪回播放
_loop = loop;
// 取得能否載入
result = true;
} catch (Exception ee) ...{
}
// 取得聲響類型
_soundType = SoundData._L_SOUNDTYPE_MIDI;
}
}
try ...{
bis.close();
} catch (Exception ee) ...{
}
break;
// Wav
case SoundData._L_SOUNDTYPE_WAV:
AudioFileFormat type = null;
// 取得Audio
try ...{
type = AudioSystem.getAudioFileFormat(bis);
} catch (Exception e) ...{
type = null;
}
// 封閉流
try ...{
bis.close();
} catch (Exception ex) ...{
}
if (type == null) ...{
return false;
}
// 依據指定信息結構數據行的信息對象
DataLine.Info di = new DataLine.Info(Clip.class, type.getFormat());
// 轉為Clip
try ...{
_audio = (Clip) AudioSystem.getLine(di);
} catch (Exception e) ...{
}
// 播放文件
try ...{
_audio.open(type.getFormat(), data, 0, data.length);
_loop = loop;
result = true;
} catch (Exception e) ...{
}
// 取得文件類型
_soundType = SoundData._L_SOUNDTYPE_WAV;
break;
}
return result;
}
public boolean play(SoundData data) ...{
if (!load(data)) ...{
return false;
}
return play();
}
public boolean play() ...{
switch (_soundType) ...{
case SoundData._L_SOUNDTYPE_MIDI:
try ...{
_midi.start();
_playing = true;
_soundType = SoundData._L_SOUNDTYPE_MIDI;
} catch (Exception ee) ...{
}
break;
case SoundData._L_SOUNDTYPE_WAV:
if (_audio != null) ...{
if (_loop) ...{
// 設定輪回
_audio.setLoopPoints(0, -1);
_audio.setFramePosition(0);
_audio.loop(Clip.LOOP_CONTINUOUSLY);
} else ...{
// 強迫設定播放地位至0
_audio.setFramePosition(0);
_audio.start();
}
_playing = true;
}
break;
}
return _playing;
}
/** *//**
* 主動播放,輪回停滯後停止。
*
* @param data
* @return
*/
public boolean AutoPlay(SoundData data) ...{
if (!load(data)) ...{
return false;
}
return AutoPlay();
}
/** *//**
* 主動播放,輪回停滯後停止。
*
* @return
*/
public boolean AutoPlay() ...{
_isRun = true;
_thread = new Thread(this);
_thread.start();
return _playing;
}
/** *//**
* 停滯播放
*/
public void stop() ...{
if (_audio != null && _audio.isActive()) ...{
try ...{
_audio.stop();
} catch (Exception e) ...{
}
}
if (_midi != null) ...{
_midi.stop();
}
_playing = false;
_isRun = false;
}
/** *//**
* 釋放數據
*
*/
public void reset() ...{
stop();
_loop = false;
_soundType = 0;
if (_midi != null) ...{
_midi.close();
_midi = null;
}
if (_audio != null && _audio.isOpen()) ...{
_audio.close();
_audio = null;
}
_isRun = false;
_thread = null;
}
/** *//**
* 設定MetaMessage
*/
public void meta(MetaMessage meta) ...{
// 斷定能否輪回播放MIDI
if (_loop && _soundType == SoundData._L_SOUNDTYPE_MIDI
&& meta.getType() == 47) ...{
if (_midi != null && _midi.isOpen()) ...{
_midi.setMicrosecondPosition(0);
_midi.start();
}
}
}
public void run() ...{
while (_isRun) ...{
play();
// 由於播放類型獨一,所以只會前往一個_playing成果,以此剖斷。
if (_midi != null) ...{
_playing = _midi.isRunning();
}
if (_audio != null) ...{
_playing = _audio.isRunning();
}
// 當播放停滯
if (!_playing) ...{
// 釋放
reset();
}
try ...{
Thread.sleep(_sleepTime);
} catch (InterruptedException e) ...{
e.printStackTrace();
}
}
}
public int getSleepTime() ...{
return _sleepTime;
}
/** *//**
* 設定AutoPlay線程輪回時光。
*
* @param time
*/
public void setSleepTime(int time) ...{
_sleepTime = time;
}
}
這時候我們須要面臨的,僅是封裝為實體的SoundData數據和SoundPlay操作,而不用和繁復的javax.sound再打交道。
挪用辦法以下:
package org.test;
import org.loon.framework.game.helper.StreamHelper;
import org.loon.framework.game.net.URI;
import org.loon.framework.game.sound.SoundData;
import org.loon.framework.game.sound.SoundPlay;
/** *//**
* <p>Title: LoonFramework</p>
* <p>Description:SoundPlay播放測試</p>
* <p>Copyright: Copyright (c) 2007</p>
* <p>Company: LoonFramework</p>
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/
public class SoundPlayTest ...{
static void selectPlay(int ftype)...{
SoundData data=null;
switch(ftype)...{
//經由過程loonframework下uri從收集播放音樂
case 0:
data=new SoundData(new URI("http://looframework.sourceforge.net/midi/誰是年夜豪傑.mid"),SoundData._L_SOUNDTYPE_MIDI,false);
break;
//經由過程當地資本下音樂文件的byte[]對象播放音樂
case 1:
byte[] bytes=StreamHelper.GetResourceData("/midi/誰是年夜豪傑.mid");
data=new SoundData(bytes,SoundData._L_SOUNDTYPE_MIDI,false);
break;
//經由過程音樂文件途徑播放音樂
case 2:
data=new SoundData("C:/誰是年夜豪傑.mid",SoundData._L_SOUNDTYPE_MIDI,false);
break;
}
SoundPlay play=new SoundPlay();
//AutoPlay與Play辦法的差別在於,AutoPlay播放終了會主動停滯並釋放資本,play需手動中斷。
//play.play(data);
play.AutoPlay(data);
}
public static void main(String[]args)...{
selectPlay(2);
}
}
更具體辦法,會待Loonframework-game完整頒布後,再停止說明。
另:因為StreamHelper聯系關系其他Loonframework中辦法,暫不給出,inputStream轉byte[]可用以下寫法:
//is為取得的inputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//用於承接byte[]
byte[] arrayByte = null;
try ...{
// 每次傳輸年夜小為4096
byte[] bytes = new byte[4096];
bytes = new byte[is.available()];
int read;
while ((read = is.read(bytes)) >= 0) ...{
byteArrayOutputStream.write(bytes, 0, read);
}
arrayByte = byteArrayOutputStream.toByteArray();
} catch (IOException e) ...{
return null;
} finally ...{
try ...{
if (byteArrayOutputStream != null) ...{
byteArrayOutputStream.close();
byteArrayOutputStream = null;
}
if (is != null) ...{
is.close();
is = null;
}
} catch (IOException e) ...{
}
}