「Java/swing/サンプル/MP3プレイヤーサンプル(JLayer,BasicPlayer,Java ID3 Tag Library)一通りの機能実装」の編集履歴(バックアップ)一覧はこちら

Java/swing/サンプル/MP3プレイヤーサンプル(JLayer,BasicPlayer,Java ID3 Tag Library)一通りの機能実装」(2013/02/22 (金) 01:54:49) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

* MP3プレイヤーサンプル(JLayer,BasicPlayer,Java ID3 Tag Library)一通りの機能実装版 &ref(BasicPlayerSample2.png) * サンプルダウンロード サンプルソース単品 &ref(BasicPlayerSample2.java) サンプルソース&必要なjarファイル &ref(BasicPlayerSample2.zip) まるっと固めたjarファイル &ref(BasicPlayerSample2_jar.zip) Windows用のexe入り &ref(BasicPlayerSample2_exe.zip) * 説明 Java/swing/BasicPlayer/Java ID3 Tag Library/JLayer BasicPlayerを使ったmp3プレイヤーサンプル第二弾 再生/停止/一時停止/プレイリスト/ループ再生/シャッフル再生/ボリューム調整/シーク/次の曲/前の曲/ID3タグv1v2読み込み ギリギリ最低限の機能をだいたい載せた気分のmp3プレイヤーサンプルです。BasicPlayerのお陰で結構簡単に作れました。 Java ID3 Tag Libraryは文字化け対応を埋め込んだ改造版です。 プレイリストは起動中に作るのみで保存も、読み込みも出来ません。そのうち実装したい… * サンプルソース(長すぎるけど #highlight(java){{ import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetAdapter; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.JTable; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.metal.MetalSliderUI; import javax.swing.table.DefaultTableModel; import javazoom.jlgui.basicplayer.BasicController; import javazoom.jlgui.basicplayer.BasicPlayer; import javazoom.jlgui.basicplayer.BasicPlayerEvent; import javazoom.jlgui.basicplayer.BasicPlayerException; import javazoom.jlgui.basicplayer.BasicPlayerListener; import org.farng.mp3.MP3File; import org.farng.mp3.TagException; import org.farng.mp3.id3.AbstractID3v2; import org.farng.mp3.id3.ID3v1; // Java/swing/BasicPlayer/Java ID3 Tag Library/JLayer // BasicPlayerを使ったmp3プレイヤーサンプル第二弾 // 再生/停止/一時停止/プレイリスト/ループ再生/シャッフル再生/ボリューム調整/シーク/次の曲/前の曲/ID3タグv1v2読み込み // ギリギリ最低限の機能をだいたい載せた気分のmp3プレイヤーサンプルです。BasicPlayerのお陰で結構簡単に作れました。 // Java ID3 Tag Libraryは文字化け対応を埋め込んだ改造版です。 // プレイリストは起動中に作るのみで保存も、読み込みも出来ません。そのうち実装したい… public class BasicPlayerSample3 extends JFrame { // ベーシックプレイヤー BasicPlayer player; // Swing用変数、定数 // ボタン用テキスト 停止 final static String STOP = "Stop"; // ボタン用テキスト 再生 final static String PLAY = "Play"; // ボタン用テキスト 一時停止 final static String PAUSE = "Pause"; // タイトル final static String TITLE = "BasicPlayerでmp3再生"; final static String FILE_NAME = "ファイル名:"; //  プレイリスト再生方法 String PL_ONE = "1曲のみ"; String PL_LIST = "プレイリスト順"; String PL_SHUFFLE = "シャッフル"; // 再生中のインデックス int playIndex; // プレイリストのモデル DefaultTableModel m; // 再生ボタン JButton bPlay; // 曲名ラベル JLabel label; // 演奏位置スライダー JSlider posSlider; // ボリュームスライダー JSlider volSlider; // 演奏位置スライダ用のリスナー ChangeListener posSliderCl; // ボリュームスライダ用のリスナー ChangeListener volSliderCl; // ループチェックボックス JCheckBox roopCheck; // プレイリストJTable JTable playList; // プレイリストの再生方法コンボボックス JComboBox plCombo; // シャッフル用のインデックスリスト ArrayList<Integer> shIndexs; // BasicPlayerからのプロパティを保存する変数 private Map audioInfo = null; // メイン関数 public static void main(String[] args) { new BasicPlayerSample3(); } // コンストラクタ public BasicPlayerSample3() { setTitle(TITLE); setDefaultCloseOperation(EXIT_ON_CLOSE); setBounds(200, 100, 300, 420); setLayout(new FlowLayout()); // ドロップターゲット設定 new DropTarget(this, DnDConstants.ACTION_COPY, new MyDropTargetListener()); // ラベル設置 label = new JLabel(" mp3ファイルをドロップしてください。"); label.setPreferredSize(new Dimension(getWidth() - 10, 20)); add(label); add(getHr(2000, 0)); // 再生、停止ボタン設置 bPlay = new JButton(PLAY); bPlay.addActionListener(new bPlayAction()); JButton bStop = new JButton(STOP); bStop.addActionListener(new bStopAction()); JButton bNext = new JButton(">>"); bNext.addActionListener(new bNextAction()); JButton bPrev = new JButton("<<"); bPrev.addActionListener(new bPrevAction()); add(bPrev); add(bPlay); add(bStop); add(bNext); // 再生位置スライダー設置 add(getHr(2000, 0)); add(new JLabel("再生位置")); posSlider = new JSlider(0, 100, 0); posSliderCl = getPosChangeListener(); posSlider.addChangeListener(posSliderCl); add(posSlider); // ボリュームスライダー設置 add(getHr(2000, 0)); add(new JLabel("ボリューム")); volSlider = new JSlider(0, 100, 50); volSliderCl = getVolChangeListener(); volSlider.addChangeListener(volSliderCl); volSlider.setUI(new TriSliderUI()); Dimension d = volSlider.getPreferredSize(); d.width = 100; volSlider.setPreferredSize(d); add(volSlider); add(getHr(2000, 0)); // プレイリスト再生方法 plCombo = new JComboBox(new String[] { PL_ONE, PL_LIST, PL_SHUFFLE }); plCombo.setSelectedIndex(1); setPlComboListener(); add(plCombo); // ループ再生チェック roopCheck = new JCheckBox("ループ再生"); add(roopCheck); // プレイリスト add(getHr(2000, 0)); m = new DefaultTableModel(new String[] { "タイトル", "アーティスト" }, 0); playList = new JTable(m); playList.setDefaultEditor(Object.class, null); // セルの編集禁止 setPlayListListener(); JScrollPane sc = new JScrollPane(playList); sc.setPreferredSize(new Dimension(280, 200)); add(sc); // BasicPlayerのインスタンス作成 player = new BasicPlayer(); addBasicPlayerListener(); setVisible(true); } // プレイリストの再生方法コンボボックスのリスナーを設定 String beforeItem; private void setPlComboListener() { plCombo.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { System.out.println(e.getStateChange()); if (e.getStateChange() == ItemEvent.SELECTED) { if (PL_SHUFFLE.equals(e.getItem())) { // シャッフルの場合 shIndexs = new ArrayList<Integer>(); for (int i = 0; i < files.size(); i++) { shIndexs.add(i); } Collections.shuffle(shIndexs); play(0); } else if (PL_SHUFFLE.equals(beforeItem)) { // シャッフルから他のアイテムになった場合 playIndex = shIndexs.get(playIndex); } } else { beforeItem = e.getItem().toString(); } } }); } // プレイリストにリスナーを設定します private void setPlayListListener() { playList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { // リストダブルクリックで該当曲再生 if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { int idx = playList.rowAtPoint(e.getPoint()); if (idx >= 0) { play(idx); } } super.mouseClicked(e); } }); } // スライダの変更通知を受け取るリスナーです private ChangeListener getPosChangeListener() { return new ChangeListener() { // スライダを操作すると通知が来ます @Override public void stateChanged(ChangeEvent e) { // マウスで操作中は何もません if (!posSlider.getValueIsAdjusting()) { // マウスで操作中でなければスライダの位置に合わせてシークします try { if (player.getStatus() == BasicPlayer.STOPPED) { // 停止中の場合、再生開始してからシークします play(); } // シーク位置計算 long l = getAudioBytes() * posSlider.getValue() / 100; player.seek(l); } catch (BasicPlayerException e1) { e1.printStackTrace(); } } } }; } // スライダの変更通知を受け取るリスナーです private ChangeListener getVolChangeListener() { return new ChangeListener() { // スライダを操作すると通知が来ます @Override public void stateChanged(ChangeEvent e) { // マウスで操作中は何もません if (!volSlider.getValueIsAdjusting()) { // マウスで操作中でなければスライダの位置に合わせてシークします setGain(); } } }; } // スライダに合わせてボリュームを設定します private void setGain() { try { player.setGain((double) volSlider.getValue() / volSlider.getMaximum()); } catch (BasicPlayerException e1) { e1.printStackTrace(); } } // BasicPlayerリスナーを追加します BasicPlayerListener bpl; private void addBasicPlayerListener() { bpl = new BasicPlayerListener() { // プレイヤーのステータス変更通知 @Override public void stateUpdated(BasicPlayerEvent event) { if (event.getCode() == BasicPlayerEvent.EOM) { try { stopAction(); } catch (BasicPlayerException e) { e.printStackTrace(); } } // プレイヤーのステータスが停止になった場合 if (player.getStatus() == BasicPlayer.STOPPED) { } } @Override public void setController(BasicController controller) { } // 再生中の進捗通知 @Override public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) { // 再生が進んだらスライダを操作します。 if (getAudioBytes() > 0) { // 新しいスライダの位置を計算します int newValue = (int) (bytesread * 100 / getAudioBytes()); // スライダをマウスで摘んでる間は操作しません // スライダの値と、現在の値が同じ場合も操作しません if (!posSlider.getValueIsAdjusting() && posSlider.getValue() != newValue) { // setValueでの操作でも、ChangeListenerに通知が行くのでリスナー取り出し、操作、リスナー追加の順に処理します posSlider.removeChangeListener(posSliderCl); posSlider.setValue(newValue); posSlider.addChangeListener(posSliderCl); } } } // ファイルオープン通知 @Override public void opened(Object stream, Map properties) { // プロパティをクラス変数に保存します audioInfo = properties; } }; player.addBasicPlayerListener(bpl); } // 曲の最後まできた時のアクション private void stopAction() throws BasicPlayerException { if (plCombo.getSelectedIndex() == 0) { // 1曲のみ if (roopCheck.isSelected()) { // ループならまた再生 // stop(); play(); } else { // ループでなければ停止 stop(); } } else if (plCombo.getSelectedIndex() == 1) { // プレイリスト順 if (roopCheck.isSelected()) { // ループなら次のファイルへ next(); } else { if (playIndex + 1 >= files.size()) { // ループじゃない&最後まで来てたら停止 stop(); } else { // 最後じゃなければ次のファイルへ next(); } } } else { // SHUFFLE if (roopCheck.isSelected()) { // ループなら次のファイルへ next(); } else { if (playIndex + 1 >= files.size()) { // ループじゃない&最後まで来てたら停止 stop(); } else { // 最後じゃなければ次のファイルへ next(); } } } } // プロパティから音楽ファイルの長さを返します private long getAudioBytes() { try { return Long.parseLong(audioInfo.get("audio.length.bytes").toString()); } catch (Exception e) { return 0; } } // 水平線 public JSeparator getHr(int width, int hight) { JSeparator sp = new JSeparator(JSeparator.HORIZONTAL); sp.setPreferredSize(new Dimension(width, hight)); return sp; } // 再生ボタンのアクションクラス class bPlayAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { int status = player.getStatus(); if (status == BasicPlayer.PAUSED) { // 一時停止の場合、一時停止を解除します resume(); } else if (status == BasicPlayer.STOPPED) { // 停止中の場合、再生開始します play(); } else if (status == BasicPlayer.PLAYING) { // 再生中の場合、一時停止します pause(); } } catch (Exception ex) { // 握りつぶす } } } // 停止ボタンのアクションクラス class bStopAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { stop(); } catch (Exception ex) { // 握りつぶす } } } // 次ボタンのアクションクラス class bNextAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { next(); } catch (Exception ex) { // 握りつぶす } } } private void next() { System.out.println("next"); play(playIndex + 1); } private void prev() { System.out.println("prev"); play(playIndex - 1); } // 前ボタンのアクションクラス class bPrevAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { prev(); } catch (Exception ex) { // 握りつぶす } } } // 一時停止 private void pause() throws BasicPlayerException { // playMode = PLAY_MODE_PAUSE; player.pause(); bPlay.setText(PLAY); } // 一時停止解除 private void resume() throws BasicPlayerException { player.resume(); bPlay.setText(PAUSE); } // 再生 private void play() throws BasicPlayerException { if (player.getStatus() != BasicPlayer.STOPPED) { player.stop(); } player.play(); bPlay.setText(PAUSE); } // インデックス指定で再生 private void play(int idx) { try { if (files.size() == 0) { return; } if (files.size() <= idx) { playIndex = 0; } else if (0 > idx) { playIndex = files.size() - 1; } else { playIndex = idx; } if (plCombo.getSelectedIndex() == 2) { // シャッフル open(files.get(shIndexs.get(playIndex))); } else { // 通常 open(files.get(playIndex)); } } catch (BasicPlayerException e) { e.printStackTrace(); } if (plCombo.getSelectedIndex() == 2) { // シャッフル playList.setRowSelectionInterval(shIndexs.get(playIndex), shIndexs.get(playIndex)); } else { // 通常 playList.setRowSelectionInterval(playIndex, playIndex); } } // 停止 private void stop() throws BasicPlayerException { if (player.getStatus() != BasicPlayer.STOPPED) { player.stop(); } bPlay.setText(PLAY); } // 開く private void open(File file) throws BasicPlayerException { if (player.getStatus() == BasicPlayer.PLAYING) { // 一旦停止してから次のファイルを再生&リスナーがいると次のファイルを再生しようとするので一旦取り出し。 player.removeBasicPlayerListener(bpl); player.stop(); for (int i = 0; i < 100; i++) { if (player.getStatus() == BasicPlayer.STOPPED) { break; } i++; try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } player.addBasicPlayerListener(bpl); } // ラベル設定 label.setText(FILE_NAME + file.getName()); // 取得したファイルを開く player.open(file); play(); // 再生 } private void setPlayList() { int rowCount = m.getRowCount(); for (int i = rowCount; i < files.size(); i++) { File f = files.get(i); m.addRow(readTag(f)); } } // mp3ファイルからID3タグを読んで表示します private String[] readTag(File file) { MP3File mp3file; String[] ret = new String[2]; try { mp3file = new MP3File(file); String title = file.getName(); String artist = "--"; // v2タグを優先的に表示 if (mp3file.hasID3v2Tag()) { AbstractID3v2 v2 = mp3file.getID3v2Tag(); title = v2.getSongTitle(); artist = v2.getLeadArtist(); } else if (mp3file.hasID3v2Tag()) { // v2タグがない場合v1タグを表示 ID3v1 v1 = mp3file.getID3v1Tag(); byte[] ary = v1.getTitle().getBytes("ISO-8859-1"); title = new String(ary); ary = v1.getArtist().getBytes("ISO-8859-1"); artist = new String(ary); } // 読み込んだタグを画面に設定 if (title == null || title.trim().length() == 0) { title = file.getName(); } ret[0] = title; ret[1] = artist; } catch (IOException e) { e.printStackTrace(); } catch (TagException e) { e.printStackTrace(); } return ret; } List<File> files = new ArrayList<File>(); // ドロップターゲットリスナー // ドロップされたファイルを受け取り、最初のファイルだけを再生します class MyDropTargetListener extends DropTargetAdapter { @Override public void drop(DropTargetDropEvent dtde) { dtde.acceptDrop(DnDConstants.ACTION_COPY); boolean b = false; try { if (dtde.getTransferable().isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { b = true; List<File> list = (List<File>) dtde.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); int idx = files.size(); // 最初のファイルだけ取得 for (File file : list) { if (file.getName().toLowerCase().endsWith("mp3")) { files.add(file); } } setPlayList(); play(idx); } } catch (Exception e) { e.printStackTrace(); } finally { dtde.dropComplete(b); } } } } // スライダー描画クラス class TriSliderUI extends MetalSliderUI { Color trackBackGroundColor = Color.LIGHT_GRAY; Color trackColor = Color.WHITE; Color trackBorderColor = Color.BLACK; Color thumbColor = Color.LIGHT_GRAY; public TriSliderUI() { super(); } public TriSliderUI(Color trackBackGroundColor, Color trackColor, Color trackBorderColor, Color thumbColor) { super(); this.trackBackGroundColor = trackBackGroundColor; this.trackColor = trackColor; this.trackBorderColor = trackBorderColor; this.thumbColor = thumbColor; } public Color getTrackBackGroundColor() { return trackBackGroundColor; } public void setTrackBackGroundColor(Color trackBackGroundColor) { this.trackBackGroundColor = trackBackGroundColor; } public Color getTrackColor() { return trackColor; } public void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackBorderColor() { return trackBorderColor; } public void setTrackBorderColor(Color trackBorderColor) { this.trackBorderColor = trackBorderColor; } public Color getThumbColor() { return thumbColor; } public void setThumbColor(Color thumbColor) { this.thumbColor = thumbColor; } // マーカー描画スレッド @Override public void paintThumb(Graphics g) { if (slider.getOrientation() == JSlider.HORIZONTAL) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setPaint(thumbColor); int x = thumbRect.x + thumbRect.width / 2 - 2; int y = thumbRect.y; int w = 5; int h = thumbRect.height; g2.fill3DRect(x, y, w, h, true); } else { super.paintThumb(g); } } // トラック描画スレッド @Override public void paintTrack(Graphics g) { int cx, cy, cw, ch; int pad; int pady = 3; Rectangle trackBounds = trackRect; if (slider.getOrientation() == JSlider.HORIZONTAL) { Graphics2D g2 = (Graphics2D) g; // いろいろ座標設定 pad = trackBuffer; cx = pad; cy = trackBounds.height / 2 - pady; cw = trackBounds.width; // アンチエイリアス設定 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.translate(trackBounds.x, trackBounds.y + cy + pady); // トラックの背景描画(ライトグレー g2.setPaint(trackBackGroundColor); Polygon polygon1 = new Polygon(); polygon1.addPoint(0, cy); polygon1.addPoint(cw, cy); polygon1.addPoint(cw, -cy); g2.fillPolygon(polygon1); // トラックの支点から現在地までの描画(白 g2.setPaint(trackColor); Polygon polygon2 = new Polygon(); polygon2.addPoint(0, cy); polygon2.addPoint(thumbRect.x, cy); polygon2.addPoint(thumbRect.x, cy - (int) (cy * 2 / (double) cw * thumbRect.x)); g2.fillPolygon(polygon2); polygon2.reset(); // 黒い枠線描画 g2.setPaint(trackBorderColor); g2.drawPolygon(polygon1); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); g2.translate(-trackBounds.x, -(trackBounds.y + cy + pady)); } else { super.paintTrack(g); } } } }} * コメント #pcomment(reply)
* MP3プレイヤーサンプル(JLayer,BasicPlayer,Java ID3 Tag Library)一通りの機能実装版 &ref(BasicPlayerSample2.png) * サンプルダウンロード サンプルソース単品 &ref(BasicPlayerSample2.java) サンプルソース&必要なjarファイル &ref(BasicPlayerSample2.zip) まるっと固めたjarファイル &ref(BasicPlayerSample2_jar.zip) Windows用のexe入り &ref(BasicPlayerSample2_exe.zip) * 新しいサンプル サンプルソース単品 &ref(BasicPlayerSample3.java) サンプルソース&必要なjarファイル &ref(BasicPlayerSample3.zip) まるっと固めたjarファイル &ref(BasicPlayerSample3_jar.zip) Windows用のexe入り &ref(BasicPlayerSample3_exe.zip) * 説明 Java/swing/BasicPlayer/Java ID3 Tag Library/JLayer BasicPlayerを使ったmp3プレイヤーサンプル第二弾 再生/停止/一時停止/プレイリスト/ループ再生/シャッフル再生/ボリューム調整/シーク/次の曲/前の曲/ID3タグv1v2読み込み ギリギリ最低限の機能をだいたい載せた気分のmp3プレイヤーサンプルです。BasicPlayerのお陰で結構簡単に作れました。 Java ID3 Tag Libraryは文字化け対応を埋め込んだ改造版です。 プレイリストは起動中に作るのみで保存も、読み込みも出来ません。そのうち実装したい… * サンプルソース(長すぎるけど #highlight(java){{ import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetAdapter; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.JTable; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.metal.MetalSliderUI; import javax.swing.table.DefaultTableModel; import javazoom.jlgui.basicplayer.BasicController; import javazoom.jlgui.basicplayer.BasicPlayer; import javazoom.jlgui.basicplayer.BasicPlayerEvent; import javazoom.jlgui.basicplayer.BasicPlayerException; import javazoom.jlgui.basicplayer.BasicPlayerListener; import org.farng.mp3.MP3File; import org.farng.mp3.TagException; import org.farng.mp3.id3.AbstractID3v2; import org.farng.mp3.id3.ID3v1; // Java/swing/BasicPlayer/Java ID3 Tag Library/JLayer // BasicPlayerを使ったmp3プレイヤーサンプル第二弾 // 再生/停止/一時停止/プレイリスト/ループ再生/シャッフル再生/ボリューム調整/シーク/次の曲/前の曲/ID3タグv1v2読み込み // ギリギリ最低限の機能をだいたい載せた気分のmp3プレイヤーサンプルです。BasicPlayerのお陰で結構簡単に作れました。 // Java ID3 Tag Libraryは文字化け対応を埋め込んだ改造版です。 // プレイリストは起動中に作るのみで保存も、読み込みも出来ません。そのうち実装したい… public class BasicPlayerSample3 extends JFrame { // ベーシックプレイヤー BasicPlayer player; // Swing用変数、定数 // ボタン用テキスト 停止 final static String STOP = "Stop"; // ボタン用テキスト 再生 final static String PLAY = "Play"; // ボタン用テキスト 一時停止 final static String PAUSE = "Pause"; // タイトル final static String TITLE = "BasicPlayerでmp3再生"; final static String FILE_NAME = "ファイル名:"; //  プレイリスト再生方法 String PL_ONE = "1曲のみ"; String PL_LIST = "プレイリスト順"; String PL_SHUFFLE = "シャッフル"; // 再生中のインデックス int playIndex; // プレイリストのモデル DefaultTableModel m; // 再生ボタン JButton bPlay; // 曲名ラベル JLabel label; // 演奏位置スライダー JSlider posSlider; // ボリュームスライダー JSlider volSlider; // 演奏位置スライダ用のリスナー ChangeListener posSliderCl; // ボリュームスライダ用のリスナー ChangeListener volSliderCl; // ループチェックボックス JCheckBox roopCheck; // プレイリストJTable JTable playList; // プレイリストの再生方法コンボボックス JComboBox plCombo; // シャッフル用のインデックスリスト ArrayList<Integer> shIndexs; // BasicPlayerからのプロパティを保存する変数 private Map audioInfo = null; // メイン関数 public static void main(String[] args) { new BasicPlayerSample3(); } // コンストラクタ public BasicPlayerSample3() { setTitle(TITLE); setDefaultCloseOperation(EXIT_ON_CLOSE); setBounds(200, 100, 300, 420); setLayout(new FlowLayout()); // ドロップターゲット設定 new DropTarget(this, DnDConstants.ACTION_COPY, new MyDropTargetListener()); // ラベル設置 label = new JLabel(" mp3ファイルをドロップしてください。"); label.setPreferredSize(new Dimension(getWidth() - 10, 20)); add(label); add(getHr(2000, 0)); // 再生、停止ボタン設置 bPlay = new JButton(PLAY); bPlay.addActionListener(new bPlayAction()); JButton bStop = new JButton(STOP); bStop.addActionListener(new bStopAction()); JButton bNext = new JButton(">>"); bNext.addActionListener(new bNextAction()); JButton bPrev = new JButton("<<"); bPrev.addActionListener(new bPrevAction()); add(bPrev); add(bPlay); add(bStop); add(bNext); // 再生位置スライダー設置 add(getHr(2000, 0)); add(new JLabel("再生位置")); posSlider = new JSlider(0, 100, 0); posSliderCl = getPosChangeListener(); posSlider.addChangeListener(posSliderCl); add(posSlider); // ボリュームスライダー設置 add(getHr(2000, 0)); add(new JLabel("ボリューム")); volSlider = new JSlider(0, 100, 50); volSliderCl = getVolChangeListener(); volSlider.addChangeListener(volSliderCl); volSlider.setUI(new TriSliderUI()); Dimension d = volSlider.getPreferredSize(); d.width = 100; volSlider.setPreferredSize(d); add(volSlider); add(getHr(2000, 0)); // プレイリスト再生方法 plCombo = new JComboBox(new String[] { PL_ONE, PL_LIST, PL_SHUFFLE }); plCombo.setSelectedIndex(1); setPlComboListener(); add(plCombo); // ループ再生チェック roopCheck = new JCheckBox("ループ再生"); add(roopCheck); // プレイリスト add(getHr(2000, 0)); m = new DefaultTableModel(new String[] { "タイトル", "アーティスト" }, 0); playList = new JTable(m); playList.setDefaultEditor(Object.class, null); // セルの編集禁止 setPlayListListener(); JScrollPane sc = new JScrollPane(playList); sc.setPreferredSize(new Dimension(280, 200)); add(sc); // BasicPlayerのインスタンス作成 player = new BasicPlayer(); addBasicPlayerListener(); setVisible(true); } // プレイリストの再生方法コンボボックスのリスナーを設定 String beforeItem; private void setPlComboListener() { plCombo.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { System.out.println(e.getStateChange()); if (e.getStateChange() == ItemEvent.SELECTED) { if (PL_SHUFFLE.equals(e.getItem())) { // シャッフルの場合 shIndexs = new ArrayList<Integer>(); for (int i = 0; i < files.size(); i++) { shIndexs.add(i); } Collections.shuffle(shIndexs); play(0); } else if (PL_SHUFFLE.equals(beforeItem)) { // シャッフルから他のアイテムになった場合 playIndex = shIndexs.get(playIndex); } } else { beforeItem = e.getItem().toString(); } } }); } // プレイリストにリスナーを設定します private void setPlayListListener() { playList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { // リストダブルクリックで該当曲再生 if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { int idx = playList.rowAtPoint(e.getPoint()); if (idx >= 0) { play(idx); } } super.mouseClicked(e); } }); } // スライダの変更通知を受け取るリスナーです private ChangeListener getPosChangeListener() { return new ChangeListener() { // スライダを操作すると通知が来ます @Override public void stateChanged(ChangeEvent e) { // マウスで操作中は何もません if (!posSlider.getValueIsAdjusting()) { // マウスで操作中でなければスライダの位置に合わせてシークします try { if (player.getStatus() == BasicPlayer.STOPPED) { // 停止中の場合、再生開始してからシークします play(); } // シーク位置計算 long l = getAudioBytes() * posSlider.getValue() / 100; player.seek(l); } catch (BasicPlayerException e1) { e1.printStackTrace(); } } } }; } // スライダの変更通知を受け取るリスナーです private ChangeListener getVolChangeListener() { return new ChangeListener() { // スライダを操作すると通知が来ます @Override public void stateChanged(ChangeEvent e) { // マウスで操作中は何もません if (!volSlider.getValueIsAdjusting()) { // マウスで操作中でなければスライダの位置に合わせてシークします setGain(); } } }; } // スライダに合わせてボリュームを設定します private void setGain() { try { player.setGain((double) volSlider.getValue() / volSlider.getMaximum()); } catch (BasicPlayerException e1) { e1.printStackTrace(); } } // BasicPlayerリスナーを追加します BasicPlayerListener bpl; private void addBasicPlayerListener() { bpl = new BasicPlayerListener() { // プレイヤーのステータス変更通知 @Override public void stateUpdated(BasicPlayerEvent event) { if (event.getCode() == BasicPlayerEvent.EOM) { try { stopAction(); } catch (BasicPlayerException e) { e.printStackTrace(); } } // プレイヤーのステータスが停止になった場合 if (player.getStatus() == BasicPlayer.STOPPED) { } } @Override public void setController(BasicController controller) { } // 再生中の進捗通知 @Override public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) { // 再生が進んだらスライダを操作します。 if (getAudioBytes() > 0) { // 新しいスライダの位置を計算します int newValue = (int) (bytesread * 100 / getAudioBytes()); // スライダをマウスで摘んでる間は操作しません // スライダの値と、現在の値が同じ場合も操作しません if (!posSlider.getValueIsAdjusting() && posSlider.getValue() != newValue) { // setValueでの操作でも、ChangeListenerに通知が行くのでリスナー取り出し、操作、リスナー追加の順に処理します posSlider.removeChangeListener(posSliderCl); posSlider.setValue(newValue); posSlider.addChangeListener(posSliderCl); } } } // ファイルオープン通知 @Override public void opened(Object stream, Map properties) { // プロパティをクラス変数に保存します audioInfo = properties; } }; player.addBasicPlayerListener(bpl); } // 曲の最後まできた時のアクション private void stopAction() throws BasicPlayerException { if (plCombo.getSelectedIndex() == 0) { // 1曲のみ if (roopCheck.isSelected()) { // ループならまた再生 // stop(); play(); } else { // ループでなければ停止 stop(); } } else if (plCombo.getSelectedIndex() == 1) { // プレイリスト順 if (roopCheck.isSelected()) { // ループなら次のファイルへ next(); } else { if (playIndex + 1 >= files.size()) { // ループじゃない&最後まで来てたら停止 stop(); } else { // 最後じゃなければ次のファイルへ next(); } } } else { // SHUFFLE if (roopCheck.isSelected()) { // ループなら次のファイルへ next(); } else { if (playIndex + 1 >= files.size()) { // ループじゃない&最後まで来てたら停止 stop(); } else { // 最後じゃなければ次のファイルへ next(); } } } } // プロパティから音楽ファイルの長さを返します private long getAudioBytes() { try { return Long.parseLong(audioInfo.get("audio.length.bytes").toString()); } catch (Exception e) { return 0; } } // 水平線 public JSeparator getHr(int width, int hight) { JSeparator sp = new JSeparator(JSeparator.HORIZONTAL); sp.setPreferredSize(new Dimension(width, hight)); return sp; } // 再生ボタンのアクションクラス class bPlayAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { int status = player.getStatus(); if (status == BasicPlayer.PAUSED) { // 一時停止の場合、一時停止を解除します resume(); } else if (status == BasicPlayer.STOPPED) { // 停止中の場合、再生開始します play(); } else if (status == BasicPlayer.PLAYING) { // 再生中の場合、一時停止します pause(); } } catch (Exception ex) { // 握りつぶす } } } // 停止ボタンのアクションクラス class bStopAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { stop(); } catch (Exception ex) { // 握りつぶす } } } // 次ボタンのアクションクラス class bNextAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { next(); } catch (Exception ex) { // 握りつぶす } } } private void next() { System.out.println("next"); play(playIndex + 1); } private void prev() { System.out.println("prev"); play(playIndex - 1); } // 前ボタンのアクションクラス class bPrevAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { prev(); } catch (Exception ex) { // 握りつぶす } } } // 一時停止 private void pause() throws BasicPlayerException { // playMode = PLAY_MODE_PAUSE; player.pause(); bPlay.setText(PLAY); } // 一時停止解除 private void resume() throws BasicPlayerException { player.resume(); bPlay.setText(PAUSE); } // 再生 private void play() throws BasicPlayerException { if (player.getStatus() != BasicPlayer.STOPPED) { player.stop(); } player.play(); bPlay.setText(PAUSE); } // インデックス指定で再生 private void play(int idx) { try { if (files.size() == 0) { return; } if (files.size() <= idx) { playIndex = 0; } else if (0 > idx) { playIndex = files.size() - 1; } else { playIndex = idx; } if (plCombo.getSelectedIndex() == 2) { // シャッフル open(files.get(shIndexs.get(playIndex))); } else { // 通常 open(files.get(playIndex)); } } catch (BasicPlayerException e) { e.printStackTrace(); } if (plCombo.getSelectedIndex() == 2) { // シャッフル playList.setRowSelectionInterval(shIndexs.get(playIndex), shIndexs.get(playIndex)); } else { // 通常 playList.setRowSelectionInterval(playIndex, playIndex); } } // 停止 private void stop() throws BasicPlayerException { if (player.getStatus() != BasicPlayer.STOPPED) { player.stop(); } bPlay.setText(PLAY); } // 開く private void open(File file) throws BasicPlayerException { if (player.getStatus() == BasicPlayer.PLAYING) { // 一旦停止してから次のファイルを再生&リスナーがいると次のファイルを再生しようとするので一旦取り出し。 player.removeBasicPlayerListener(bpl); player.stop(); for (int i = 0; i < 100; i++) { if (player.getStatus() == BasicPlayer.STOPPED) { break; } i++; try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } player.addBasicPlayerListener(bpl); } // ラベル設定 label.setText(FILE_NAME + file.getName()); // 取得したファイルを開く player.open(file); play(); // 再生 } private void setPlayList() { int rowCount = m.getRowCount(); for (int i = rowCount; i < files.size(); i++) { File f = files.get(i); m.addRow(readTag(f)); } } // mp3ファイルからID3タグを読んで表示します private String[] readTag(File file) { MP3File mp3file; String[] ret = new String[2]; try { mp3file = new MP3File(file); String title = file.getName(); String artist = "--"; // v2タグを優先的に表示 if (mp3file.hasID3v2Tag()) { AbstractID3v2 v2 = mp3file.getID3v2Tag(); title = v2.getSongTitle(); artist = v2.getLeadArtist(); } else if (mp3file.hasID3v2Tag()) { // v2タグがない場合v1タグを表示 ID3v1 v1 = mp3file.getID3v1Tag(); byte[] ary = v1.getTitle().getBytes("ISO-8859-1"); title = new String(ary); ary = v1.getArtist().getBytes("ISO-8859-1"); artist = new String(ary); } // 読み込んだタグを画面に設定 if (title == null || title.trim().length() == 0) { title = file.getName(); } ret[0] = title; ret[1] = artist; } catch (IOException e) { e.printStackTrace(); } catch (TagException e) { e.printStackTrace(); } return ret; } List<File> files = new ArrayList<File>(); // ドロップターゲットリスナー // ドロップされたファイルを受け取り、最初のファイルだけを再生します class MyDropTargetListener extends DropTargetAdapter { @Override public void drop(DropTargetDropEvent dtde) { dtde.acceptDrop(DnDConstants.ACTION_COPY); boolean b = false; try { if (dtde.getTransferable().isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { b = true; List<File> list = (List<File>) dtde.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); int idx = files.size(); // 最初のファイルだけ取得 for (File file : list) { if (file.getName().toLowerCase().endsWith("mp3")) { files.add(file); } } setPlayList(); play(idx); } } catch (Exception e) { e.printStackTrace(); } finally { dtde.dropComplete(b); } } } } // スライダー描画クラス class TriSliderUI extends MetalSliderUI { Color trackBackGroundColor = Color.LIGHT_GRAY; Color trackColor = Color.WHITE; Color trackBorderColor = Color.BLACK; Color thumbColor = Color.LIGHT_GRAY; public TriSliderUI() { super(); } public TriSliderUI(Color trackBackGroundColor, Color trackColor, Color trackBorderColor, Color thumbColor) { super(); this.trackBackGroundColor = trackBackGroundColor; this.trackColor = trackColor; this.trackBorderColor = trackBorderColor; this.thumbColor = thumbColor; } public Color getTrackBackGroundColor() { return trackBackGroundColor; } public void setTrackBackGroundColor(Color trackBackGroundColor) { this.trackBackGroundColor = trackBackGroundColor; } public Color getTrackColor() { return trackColor; } public void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackBorderColor() { return trackBorderColor; } public void setTrackBorderColor(Color trackBorderColor) { this.trackBorderColor = trackBorderColor; } public Color getThumbColor() { return thumbColor; } public void setThumbColor(Color thumbColor) { this.thumbColor = thumbColor; } // マーカー描画スレッド @Override public void paintThumb(Graphics g) { if (slider.getOrientation() == JSlider.HORIZONTAL) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setPaint(thumbColor); int x = thumbRect.x + thumbRect.width / 2 - 2; int y = thumbRect.y; int w = 5; int h = thumbRect.height; g2.fill3DRect(x, y, w, h, true); } else { super.paintThumb(g); } } // トラック描画スレッド @Override public void paintTrack(Graphics g) { int cx, cy, cw, ch; int pad; int pady = 3; Rectangle trackBounds = trackRect; if (slider.getOrientation() == JSlider.HORIZONTAL) { Graphics2D g2 = (Graphics2D) g; // いろいろ座標設定 pad = trackBuffer; cx = pad; cy = trackBounds.height / 2 - pady; cw = trackBounds.width; // アンチエイリアス設定 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.translate(trackBounds.x, trackBounds.y + cy + pady); // トラックの背景描画(ライトグレー g2.setPaint(trackBackGroundColor); Polygon polygon1 = new Polygon(); polygon1.addPoint(0, cy); polygon1.addPoint(cw, cy); polygon1.addPoint(cw, -cy); g2.fillPolygon(polygon1); // トラックの支点から現在地までの描画(白 g2.setPaint(trackColor); Polygon polygon2 = new Polygon(); polygon2.addPoint(0, cy); polygon2.addPoint(thumbRect.x, cy); polygon2.addPoint(thumbRect.x, cy - (int) (cy * 2 / (double) cw * thumbRect.x)); g2.fillPolygon(polygon2); polygon2.reset(); // 黒い枠線描画 g2.setPaint(trackBorderColor); g2.drawPolygon(polygon1); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); g2.translate(-trackBounds.x, -(trackBounds.y + cy + pady)); } else { super.paintTrack(g); } } } }} * コメント #pcomment(reply)

表示オプション

横に並べて表示:
変化行の前後のみ表示: