Implemented seek functionality.

This commit is contained in:
neviyn 2016-02-28 22:18:15 +00:00
parent 587324d5ef
commit bc53f088cf
4 changed files with 87 additions and 2 deletions

View File

@ -2,6 +2,7 @@ package musicplayer;
import musicplayer.callbacks.PlayerCallbackInterface; import musicplayer.callbacks.PlayerCallbackInterface;
import musicplayer.model.Song; import musicplayer.model.Song;
import org.gstreamer.ClockTime;
import org.gstreamer.ElementFactory; import org.gstreamer.ElementFactory;
import org.gstreamer.Gst; import org.gstreamer.Gst;
import org.gstreamer.State; import org.gstreamer.State;
@ -115,7 +116,7 @@ public class Player {
* @return Current playback position in seconds. * @return Current playback position in seconds.
*/ */
public int currentSongPosition(){ public int currentSongPosition(){
return playBin.isPlaying() || playBin.getState() == State.PAUSED ? (int) (playBin.getClock().getTime().toSeconds() - playBin.getBaseTime().toSeconds()) : 0; return playBin.isPlaying() || playBin.getState() == State.PAUSED ? (int) playBin.queryPosition().toSeconds() : 0;
} }
/** /**
@ -134,6 +135,14 @@ public class Player {
return playBin.getVolumePercent(); return playBin.getVolumePercent();
} }
/**
* Seek to a position in the song.
* @param position Position (in seconds) to seek to.
*/
public void seek(int position){
playBin.seek(ClockTime.fromSeconds(position));
}
private class InternalThread implements Runnable { private class InternalThread implements Runnable {
@Override @Override

View File

@ -16,10 +16,12 @@ import java.awt.*;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface { public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface {
@ -32,6 +34,7 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>()); private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>());
private static DefaultMutableTreeNode updatingNode = new DefaultMutableTreeNode(); private static DefaultMutableTreeNode updatingNode = new DefaultMutableTreeNode();
private boolean libraryUpdating = false; private boolean libraryUpdating = false;
private AtomicBoolean seeking = new AtomicBoolean(false);
private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap(); private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
@ -69,7 +72,10 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
* @param position New seekBar value. * @param position New seekBar value.
*/ */
public void setSeekBarPosition(int position) { public void setSeekBarPosition(int position) {
SwingUtilities.invokeLater(() -> seekBar.setValue(position)); SwingUtilities.invokeLater(() -> {
if(!seeking.get())
seekBar.setValue(position);
});
} }
/** /**
@ -153,6 +159,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
player.playSong(playlistTableModel.nextSong(player.getCurrentSong())); player.playSong(playlistTableModel.nextSong(player.getCurrentSong()));
} }
/**
* Get the previous song in the playlist and dispatch it to the Player to be played.
*/
public void playPreviousSong() { public void playPreviousSong() {
SwingUtilities.invokeLater(() -> seekBar.setValue(0)); SwingUtilities.invokeLater(() -> seekBar.setValue(0));
player.playSong(playlistTableModel.previous(player.getCurrentSong())); player.playSong(playlistTableModel.previous(player.getCurrentSong()));
@ -222,6 +231,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
((DefaultTreeModel)libraryView.getModel()).nodeChanged(updatingNode); ((DefaultTreeModel)libraryView.getModel()).nodeChanged(updatingNode);
} }
/**
* @return Map of display types for the library paired code to populate the library with data in the correct format.
*/
private Map<String, Runnable> createDisplayVariantMap() { private Map<String, Runnable> createDisplayVariantMap() {
Map<String, Runnable> value = new HashMap<>(); Map<String, Runnable> value = new HashMap<>();
value.put("Song", () -> Gateway.listAllSongs().ifPresent(this::populateLibrary)); value.put("Song", () -> Gateway.listAllSongs().ifPresent(this::populateLibrary));
@ -272,11 +284,15 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
seekBar = new JSlider(); seekBar = new JSlider();
seekBar.setMinorTickSpacing(1); seekBar.setMinorTickSpacing(1);
seekBar.setValue(0); seekBar.setValue(0);
seekBar.addMouseListener(new SeekbarMouseListener());
controlPane.add(seekBar, BorderLayout.NORTH); controlPane.add(seekBar, BorderLayout.NORTH);
controlPane.add(createControlButtons(), BorderLayout.SOUTH); controlPane.add(createControlButtons(), BorderLayout.SOUTH);
mainPanel.add(createMenuBar(), BorderLayout.NORTH); mainPanel.add(createMenuBar(), BorderLayout.NORTH);
} }
/**
* @return Area containing the library.
*/
private JTree createLibraryArea() { private JTree createLibraryArea() {
libraryView.setRootVisible(false); libraryView.setRootVisible(false);
libraryView.setToggleClickCount(1); libraryView.setToggleClickCount(1);
@ -285,6 +301,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
return libraryView; return libraryView;
} }
/**
* @return Area containing the playlist.
*/
private JScrollPane createPlaylistArea() { private JScrollPane createPlaylistArea() {
JScrollPane playlistScroll = new JScrollPane(); JScrollPane playlistScroll = new JScrollPane();
playList.setRowSelectionAllowed(true); playList.setRowSelectionAllowed(true);
@ -308,6 +327,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
return playlistScroll; return playlistScroll;
} }
/**
* @return Playback control buttons (play, stop, etc.)
*/
private JToolBar createControlButtons() { private JToolBar createControlButtons() {
JToolBar toolBar = new JToolBar(); JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false); toolBar.setFloatable(false);
@ -345,6 +367,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
return toolBar; return toolBar;
} }
/**
* @return Volume controls.
*/
private JPanel createVolumeControls() { private JPanel createVolumeControls() {
JPanel panel = new JPanel(); JPanel panel = new JPanel();
panel.setLayout(new FlowLayout()); panel.setLayout(new FlowLayout());
@ -410,4 +435,29 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
} }
} }
} }
/**
* MouseListener implementation for the seekbar.
* Using this instead of the ChangeListener so that the polling for the current song position
* doesn't repeatedly fire seek events.
*/
private class SeekbarMouseListener implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) { seeking.set(true); }
@Override
public void mousePressed(MouseEvent e) { seeking.set(true); }
@Override
public void mouseReleased(MouseEvent e) {
player.seek(seekBar.getValue());
seeking.set(false);
}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
}
} }

View File

@ -2,7 +2,15 @@ package musicplayer.callbacks;
public interface LibraryCallbackInterface { public interface LibraryCallbackInterface {
/**
* Call this after performing library updates so the front-end knows that updating has completed.
* @param successful Was the update function successful.
*/
void libraryUpdated(boolean successful); void libraryUpdated(boolean successful);
/**
* Update the current display with the file/folder currently being parsed.
* @param name Data about the file/folder to be shown to the user.
*/
void currentlyUpdating(String name); void currentlyUpdating(String name);
} }

View File

@ -6,14 +6,32 @@ import java.util.Optional;
public interface PlayerCallbackInterface { public interface PlayerCallbackInterface {
/**
* Set the song currently shown to the user as playing.
* @param playingSong Song currently playing.
*/
void setSongHighlighting(Song playingSong); void setSongHighlighting(Song playingSong);
/**
* Set the seekbar position.
* @param seconds Position to set the seekbar to.
*/
void setSeekBarDuration(int seconds); void setSeekBarDuration(int seconds);
/**
* Remove a song from the current playlist.
* @param invalidSong Song to remove.
*/
void removeInvalidSong(Song invalidSong); void removeInvalidSong(Song invalidSong);
/**
* Playback has ceased.
*/
void playerStopped(); void playerStopped();
/**
* Start playing the next song.
*/
void playNextSong(); void playNextSong();
} }