程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 實例解析應用Java完成根本的音頻播放器的編寫要點

實例解析應用Java完成根本的音頻播放器的編寫要點

編輯:關於JAVA

實例解析應用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:[email protected]
 * @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:[email protected]
 * @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:[email protected]
 * @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:[email protected] 
 * @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) ...{
      }
    }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved