Java/swing/サンプル/BasicPlayerサンプル(mp3, シーク, 時間表示)


サンプルダウンロード


スクロールバーと時間表示用ラベル設定

// シークバー
    seekBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 0, 0, 1000);
    seekBar.setPreferredSize(new Dimension(200, seekBar.getPreferredSize().height));
    // ChangeListener設置
    seekBar.addAdjustmentListener(al);
    // 音量調整スライダー設置
    add(seekBar);
 
    // スライダー用ラベル設置
    timeLabel = new JLabel("00:00");
    add(timeLabel);
 
  • JScrollBarとJLabelで、シーク時間指定用のスクロールバーと、時間表示用のラベルを設定します。
  • コンストラクタでは、横向き、初期値0、エクステント(掴む所の値)、最小値0、最大値1000で作成しています。
  • setPreferredSizeで、シークバーの横幅を変更しています。

スクロールバーを操作した時のリスナー作成

  • スクロールバーを操作すると、AdjustmentListenerでイベントを受け取ることができます。
AdjustmentListener al = new AdjustmentListener() {
    @Override
    public void adjustmentValueChanged(AdjustmentEvent e) {
      if (!seekBar.getValueIsAdjusting()) {
        try {
          // シーク位置計算
          long bytes = Long.parseLong(audioInfo.get("audio.length.bytes").toString());
          long seek = bytes * seekBar.getValue() / seekBar.getMaximum();
 
          // シーク
          player.removeBasicPlayerListener(bpl);
          player.seek(seek);
          player.addBasicPlayerListener(bpl);
        } catch (NumberFormatException e1) {
          e1.printStackTrace();
        } catch (BasicPlayerException e1) {
          e1.printStackTrace();
        }
      }
    }
  };
 
  • スクロールバーの変更イベントを受け取ったら、シーク位置を計算してBasicPlayer#seekでシーク(再生位置を変更)します。
  • シーク位置の計算は、BasicPlayerから受け取ったMapから、ファイルサイズ(audio.length.bytes)を取得し、「ファイルサイズ / シークバーの現在値 * シークバーの最大値」で計算できます。
  • シークの直前にBasicPlayerから、BasicPlayerListenerを取り出してからシークします。
    • こうすることで、シークバーのブレを抑えることができます。

BasicPlayerからのイベントを受け取る

BasicPlayerListener bpl = new BasicPlayerListener() {
    @Override
    public void stateUpdated(BasicPlayerEvent event) {
    }
 
    @Override
    public void setController(BasicController controller) {
    }
 
    @Override
    public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) {
      long total = Long.parseLong(audioInfo.get("audio.length.bytes").toString());
      int newValue = (int) ((double) bytesread / total * seekBar.getMaximum());
      if (newValue != seekBar.getValue() && !seekBar.getValueIsAdjusting()) {
        seekBar.removeAdjustmentListener(al);
 
        // トータル秒数計算
        long bitrate = Long.parseLong(audioInfo.get("bitrate").toString());
        int seconds = (int) (total / (bitrate / 8));
 
        // 現在の秒数
        int nowSecond = (int) (bytesread * seconds / total);
 
        // 分と秒を計算
        int tm = seconds / 60;
        int ts = seconds % 60;
        int m = nowSecond / 60;
        int s = nowSecond % 60;
 
        seekBar.setValue(newValue);
        timeLabel.setText(String.format("%1$02d:%2$02d / %3$02d:%4$02d", m, s, tm, ts));
        seekBar.addAdjustmentListener(al);
      }
    }
 
    @Override
    public void opened(Object stream, Map properties) {
      audioInfo = properties;
    }
  };
 
  • シークバーを作ったなら、再生位置に合わせての時間表示とバーの更新を行いたい
    • その為に使えるのが、BasicPlayerListenerです。
  • BasicPlayerListener#opened
    • BasicPlayerが曲情報を読み取ると、BasicPlayerListener#openedでイベントを受け取れます。
    • ここでは、パラメータのpropertiesをクラス変数に保存して、シーク位置や再生時間の計算に活用します。
  • BasicPlayerListener#progress
    • 曲の再生が進む度にBasicPlayerListener#progressでイベントを受け取れます。
    • 曲情報のビットレートとファイルサイズから曲の長さを求め
    • パラメータのbytesreadと曲の長さ、ファイルサイズから現在の再生時間を求めます
    • パラメータのbytesreadと、ファイルサイズ、シークバーの最大値から、シークバーの新しい値を求めてシークバーに設定します。
    • シークバーの値を変更する時も、リスナーを取り出してから変更します。
      • リスナーを取り出さないと、シークバーの値変更でリスナーにシークイベントが伝わってしまうのです。

コメント

名前: