JavaでWAV再生、シンプルメディアプレーヤーの作成


Posted on 2021/6/25 at 22:58


Javaで音声(WAV)ファイルを再生するサンプルはネット上にいくつもあったので、それを参考にしてSwingにてシンプルプレーヤーを作成してみました。主な機能は以下の3つだけです。

  1. 一時停止は無く「再生」か「停止」
  2. スライダーによるボリュームの調整
  3. 再生ファイルの選択

サンプルコード

  
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

public class SimplePlayer extends JFrame {

	private VolumeChangeListener volumeChangeListener = null;
	private Clip clip = null;
	private JButton playBtn;
	private JTextField mediaPathTxt;
	private VolumeSlider slider;
	
	public static void main(String[] args) {
		new SimplePlayer();
	}

	public SimplePlayer() {
		super("simple player");
		this.setSize(700, 75);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		JPanel p = new JPanel();
		p.setLayout(new FlowLayout(FlowLayout.LEADING));
		
		playBtn = new JButton("再生");
		playBtn.setPreferredSize(new Dimension(60, 25));
		playBtn.setFont(new Font(playBtn.getFont().getFontName(), Font.PLAIN, 12));
		playBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (mediaPathTxt.getText().isEmpty()) {
					JOptionPane.showMessageDialog(
							SimplePlayer.this, "音声ファイルを選択してください。", "エラー", 
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				JButton source = (JButton) e.getSource();
				if (source.getText().equals("再生")) {
					PlayWorker worker = new PlayWorker();
					worker.execute();
					return;
				}
				StopWorker worker = new StopWorker();
				worker.execute();
			}
		});
		mediaPathTxt = new JTextField();
		mediaPathTxt.setPreferredSize(new Dimension(300, 25));
		JButton fileBtn = new JButton("参照");
		fileBtn.setPreferredSize(new Dimension(60, 25));
		fileBtn.setFont(new Font(fileBtn.getFont().getFontName(), Font.PLAIN, 12));
		fileBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				FileFilter filter = new FileNameExtensionFilter("wavファイル(.wav)", "wav");
				chooser.setSelectedFile(new File(mediaPathTxt.getText()));
				chooser.setFileFilter(filter);
				int selected = chooser.showOpenDialog(SimplePlayer.this);
				if (selected == JFileChooser.APPROVE_OPTION) {
					File file = chooser.getSelectedFile();
					mediaPathTxt.setText(file.getAbsolutePath());
				}
			}
		});
		slider = new VolumeSlider();
		p.add(playBtn);
		p.add(mediaPathTxt);
		p.add(fileBtn);
		p.add(slider);
		this.getContentPane().add(p);
		this.setVisible(true);
	}
	
	class PlayWorker extends SwingWorker {
		private AudioInputStream stream = null;
		@Override
		protected Void doInBackground() throws Exception {
			AudioFormat format = null;
			try {
				playBtn.setText("停止");
				stream = AudioSystem.getAudioInputStream(new File(mediaPathTxt.getText()));
				format = stream.getFormat();
				DataLine.Info cInfo = new DataLine.Info(Clip.class, format);
				if (!AudioSystem.isLineSupported(cInfo))
					return null;
				clip = (Clip) AudioSystem.getLine(cInfo);
				clip.open(stream);
				float volume = (float) ((float)slider.getValue() / 100f);
				FloatControl ctrl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
				ctrl.setValue((float) Math.log10(volume) * 20);
				volumeChangeListener = new VolumeChangeListener();
				clip.addLineListener(volumeChangeListener);
				clip.start();
				clip.flush();
				while (clip.isActive())
					Thread.sleep(50);
			} catch (UnsupportedAudioFileException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (LineUnavailableException e) {
				e.printStackTrace();
			} catch (InterruptedException e1) {
			}
			return null;
		}
		
		@Override
		public void done() {
			try {
				playBtn.setText("再生");
			} finally {
				if (clip != null && clip.isOpen())
					clip.close();
				try {
					if(stream != null)
						stream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	class StopWorker extends SwingWorker {
		@Override
		protected Void doInBackground() throws Exception {
			playBtn.setText("再生");
			if (clip != null && clip.isOpen()) {
				clip.stop();
				clip.flush();
			}
			return null;
		}
		@Override
		public void done() {
			playBtn.setText("再生");
		}
	}
	
	class VolumeSlider extends JSlider {
		public VolumeSlider() {
			super(0, 100, 20);
			this.setMajorTickSpacing(25);
			this.setPaintLabels(true);
			this.addChangeListener(new ChangeListener() {
				@Override
				public void stateChanged(ChangeEvent e) {
					if (volumeChangeListener != null)
						volumeChangeListener.fireVolumeChange();
				}
			});
		}
	}
	
	class VolumeChangeListener implements LineListener {
		public void fireVolumeChange() {
			float volume = (float) ((float)slider.getValue() / 100f);
			FloatControl ctrl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
			ctrl.setValue((float)Math.log10(volume) * 20);
		}
		@Override
		public void update(LineEvent event) {}
	}

}

  

プログラムの実行結果

関連記事

JavaでWAVファイルをリピート再生する

再生する音声ファイル、ボリューム(0~1)、リピートする回数、リピートの間隔(ms)を指定して再生するサンプルコードです。