package vazkii.minetunes.player;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.JavaSoundAudioDevice;
import javazoom.jl.player.advanced.AdvancedPlayer;
import javazoom.jl.player.advanced.PlaybackEvent;
import javazoom.jl.player.advanced.PlaybackListener;
import vazkii.minetunes.gui.GuiDevTools;
import vazkii.minetunes.gui.GuiPlaylistManager;
import vazkii.minetunes.playlist.MP3Metadata;
import vazkii.minetunes.playlist.Playlist;
public class ThreadMusicPlayer extends Thread {
public static final float MIN_GAIN = -20F;
public static final float MAX_GAIN = 0F;
public static final float MED_GAIN = (MAX_GAIN - MIN_GAIN) / 2 * (Math.abs(MIN_GAIN) / MIN_GAIN);
public volatile static float gain = MED_GAIN;
EventListener listener = new EventListener();
AdvancedPlayer player;
volatile MP3Metadata playingMP3;
volatile boolean queued = false;
volatile boolean kill = false;
volatile boolean playing = false;
volatile boolean paused = false;
volatile int pauseFrames = 0;
volatile List<MP3Metadata> lastSongs = new ArrayList();
public ThreadMusicPlayer() {
setDaemon(true);
setName("mineTunes Player Thread");
start();
}
@Override
public void run() {
try {
GuiDevTools.debugLog("Starting " + this);
while(!kill) {
if(queued && playingMP3 != null) {
GuiDevTools.debugLog("Queued: " + playingMP3.file.getAbsolutePath());
if(player != null)
resetPlayer();
player = new AdvancedPlayer(new FileInputStream(playingMP3.file));
player.setPlayBackListener(listener);
queued = false;
GuiDevTools.debugLog("Player (Re)loaded");
}
boolean played = false;
if(player != null && player.getAudioDevice() != null) {
if(pauseFrames == 0) {
GuiDevTools.debugLog("Playing File");
player.play();
playing = true;
} else if(!paused) {
GuiDevTools.debugLog("Was paused, restarting at " + pauseFrames);
int startFrame = pauseFrames;
pauseFrames = 0;
player.play(startFrame, Integer.MAX_VALUE);
playing = true;
}
played = true;
}
if(played && !paused && !queued) {
GuiDevTools.debugLog("Song done, next...");
next();
}
}
} catch(Exception e) {
GuiDevTools.logThrowable(e);
}
}
public void next() {
next(true);
}
public void next(boolean add) {
Playlist playlist = GuiPlaylistManager.getCurrentPlaylist();
MP3Metadata mp3 = playlist == null ? null : playlist.nextSong();
if(mp3 != null)
play(mp3, add);
else {
playingMP3 = null;
resetPlayer();
}
}
public void prev() {
if(lastSongs.size() < 2)
return;
removeFromLastPlayed(lastSongs.get(lastSongs.size() - 1));
MP3Metadata meta = lastSongs.get(lastSongs.size() - 1);
play(meta, false);
}
public void resetPlayer() {
GuiDevTools.debugLog("Resetting Player.");
playing = false;
if(player != null)
player.close();
player = null;
}
public void play(MP3Metadata metadata) {
play(metadata, true);
}
public void play(MP3Metadata metadata, boolean add) {
resetPlayer();
if(add)
addToLastPlayed(metadata);
playingMP3 = metadata;
paused = false;
queued = true;
}
private void addToLastPlayed(MP3Metadata meta) {
lastSongs.add(meta);
while(lastSongs.size() > 10)
lastSongs.remove(0);
}
private void removeFromLastPlayed(MP3Metadata meta) {
lastSongs.remove(meta);
}
public void pauseOrPlay() {
if(player != null)
if(!paused) {
GuiDevTools.debugLog("Pausing...");
paused = true;
if(player.getAudioDevice() != null)
player.stop();
} else {
GuiDevTools.debugLog("Unpaused...");
queued = true;
paused = false;
}
}
public void onPlaylistChange() {
lastSongs.clear();
}
public float getGain() {
if(player == null)
return gain;
AudioDevice device = player.getAudioDevice();
if(device != null && device instanceof JavaSoundAudioDevice)
return ((JavaSoundAudioDevice) device).getGain();
return gain;
}
public void addGain(float gain) {
setGain(getGain() + gain);
}
public void setGain(float gain) {
if(player == null)
return;
this.gain = Math.min(MAX_GAIN, Math.max(MIN_GAIN, gain));
AudioDevice device = player.getAudioDevice();
if(device != null && device instanceof JavaSoundAudioDevice)
((JavaSoundAudioDevice) device).setGain(this.gain);
}
public float getRelativeVolume() {
return getRelativeVolume(getGain());
}
public float getRelativeVolume(float gain) {
float width = MAX_GAIN - MIN_GAIN;
float rel = Math.abs(gain - MIN_GAIN);
return rel / Math.abs(width);
}
public MP3Metadata getPlayingMetadata() {
return playingMP3;
}
public int getFramesPlayed() {
return player == null ? 0 : player.getFrames();
}
public float getFractionPlayed() {
int pFrames = getFramesPlayed();
int tFrames = playingMP3 == null ? 0 : playingMP3.frameCount;
if(pFrames == 0 || tFrames == 0)
return 0F;
return (float) pFrames / (float) tFrames;
}
public boolean isPaused() {
return paused && playingMP3 != null;
}
public void forceKill() {
try {
resetPlayer();
interrupt();
finalize();
kill = true;
} catch(Throwable e) {
GuiDevTools.logThrowable(e);
}
}
class EventListener extends PlaybackListener {
@Override
public void playbackFinished(PlaybackEvent evt) {
if(paused) {
pauseFrames = evt.getSource().getFrames();
GuiDevTools.debugLog("Paused at " + pauseFrames);
}
}
}
}