国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

實例解析使用Java實現基本的音頻播放器的編寫要點

2019-11-26 14:41:37
字體:
來源:轉載
供稿:網友

 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) ...{      }    }

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 辽阳县| 讷河市| 三门县| 阿尔山市| 涟源市| 沐川县| 玉门市| 安溪县| 郯城县| 辽阳县| 藁城市| 岳普湖县| 凤山县| 大渡口区| 东兰县| 柘城县| 大埔县| 平远县| 唐河县| 分宜县| 新巴尔虎右旗| 青川县| 九江市| 临泽县| 岢岚县| 德兴市| 马公市| 阿坝| 鞍山市| 孟州市| 孝昌县| 绥中县| 东光县| 明星| 宁德市| 即墨市| 涞水县| 临沂市| 辰溪县| 沙雅县| 山阴县|