package logbook.gui.logic; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.FloatControl; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; import logbook.config.AppConfig; import logbook.internal.LoggerHolder; import org.apache.commons.io.FileUtils; /** * サウンドを操作します * */ public final class Sound { /** 再生待ち */ private static ArrayBlockingQueue<File> soundfileQueue = new ArrayBlockingQueue<File>(10); /** ロガー */ private static final LoggerHolder LOG = new LoggerHolder(Sound.class); /** バッファーサイズ */ private static final int BUFFER_SIZE = 1024 * 8; /** 拡張子 */ private static final String[] EXTENSIONS = { "wav" }; /** * サウンドファイルを再生待ちキューに入れます * * @param file ファイル */ public static void addQueue(File file) { soundfileQueue.offer(file); } /** * サウンドファイルを再生します * * @param file ファイル */ public static void play(File file) { try { AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); try { AudioFormat audioFormat = audioInputStream.getFormat(); // データラインの情報オブジェクトを生成します DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); // 指定されたデータライン情報に一致するラインを取得します SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); try { // 指定されたオーディオ形式でラインを開きます line.open(audioFormat); // ラインでのデータ入出力を可能にします line.start(); // ゲインのコントロールを取得します FloatControl control = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); // サウンド音量を設定 controlByLinearScalar(control, AppConfig.get().getSoundLevel()); int nBytesRead = 0; byte[] abData = new byte[BUFFER_SIZE]; while (nBytesRead != -1) { // オーディオストリームからデータを読み込みます nBytesRead = audioInputStream.read(abData, 0, abData.length); if (nBytesRead >= 0) { // オーディオデータをミキサーに書き込みます line.write(abData, 0, nBytesRead); } } line.drain(); } finally { line.close(); } } finally { audioInputStream.close(); } } catch (UnsupportedAudioFileException e) { LOG.get().warn("サポートされていないサウンドファイル形式です", file); } catch (Exception e) { LOG.get().warn("サウンドの再生に失敗しました", e); } } /** * リストからランダムにサウンドファイルを再生します * * @param files ファイルリスト */ public static void randomPlay(List<File> files) { if (files.size() > 0) { addQueue(files.get((int) (Math.random() * files.size()))); } } /** * 遠征から帰投した時に再生するサウンドを再生します * */ public static void randomExpeditionSoundPlay() { randomPlay(getFileList("./sound/expedition")); } /** * お風呂からあがる時に再生するサウンドを再生します * */ public static void randomDockSoundPlay() { randomPlay(getFileList("./sound/dock")); } /** * 泊地修理した時に再生するサウンドを再生します * */ public static void randomAkashiSoundPlay() { randomPlay(getFileList("./sound/akashi")); } /** * 疲労が回復した時に再生するサウンドを再生します * */ public static void randomCondSoundPlay() { randomPlay(getFileList("./sound/condition")); } /** * 大破した時に再生するサウンドを再生します * */ public static void randomBadlySoundPlay() { randomPlay(getFileList("./sound/badly")); } public static void randomWarningPlay() { randomPlay(getFileList("./sound/warning")); } /** * 遠征から帰投した時に再生するサウンドを取得します * * @return サウンドファイル */ private static List<File> getFileList(String path) { File expedition = new File(path); if (expedition.exists() && expedition.isDirectory()) { return new ArrayList<File>(FileUtils.listFiles(expedition, EXTENSIONS, true)); } return Collections.emptyList(); } /** * 音量を調節する * * @param control * @param linearScalar */ private static void controlByLinearScalar(FloatControl control, double linearScalar) { control.setValue((float) Math.log10(linearScalar) * 20); } /** * プレイヤースレッド * */ public static class PlayerThread extends Thread { /** ロガー */ private static final LoggerHolder LOG = new LoggerHolder(PlayerThread.class); /** * プレイヤースレッド */ public PlayerThread() { this.setName("logbook_sound.player_thread"); } @Override public void run() { try { while (true) { File file = soundfileQueue.take(); if (file != null) { play(file); } //Thread.sleep(500); } } catch (Exception e) { LOG.get().fatal("スレッドが異常終了しました", e); throw new RuntimeException(e); } } } }