Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Plays a list of Audio Files in JavaFX, displaying the media metadata of each file (it it is available).
import javafx.application.*;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.media.*;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.Duration;
import java.io.File;
import java.io.FilenameFilter;
import java.util.*;
/** Example of playing all audio files in a given directory. */
public class AudioPlaylist extends Application {
private static final String MUSIC_DIR = "/Users/lilyshard/Music";
public static final String TAG_COLUMN_NAME = "Tag";
public static final String VALUE_COLUMN_NAME = "Value";
public static final List<String> SUPPORTED_FILE_EXTENSIONS = Arrays.asList(".mp3", ".m4a");
public static final int FILE_EXTENSION_LEN = 3;
final Label currentlyPlaying = new Label();
final ProgressBar progress = new ProgressBar();
final TableView<Map> metadataTable = new TableView<>();
private ChangeListener<Duration> progressChangeListener;
private MapChangeListener<String, Object> metadataChangeListener;
public static void main(String[] args) throws Exception { launch(args); }
public void start(final Stage stage) throws Exception {
stage.setTitle("Simple Audio Player");
// determine the source directory for the playlist (either the first argument to the program or a default).
final List<String> params = getParameters().getRaw();
final File dir = (params.size() > 0)
? new File(params.get(0))
: new File(MUSIC_DIR);
if (!dir.exists() || !dir.isDirectory()) {
System.out.println("Cannot find audio source directory: " + dir + " please supply a directory as a command line argument");
Platform.exit();
return;
}
// create some media players.
final List<MediaPlayer> players = new ArrayList<>();
for (String file : dir.list(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
for (String ext: SUPPORTED_FILE_EXTENSIONS) {
if (name.endsWith(ext)) {
return true;
}
}
return false;
}
})) players.add(createPlayer("file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20")));
if (players.isEmpty()) {
System.out.println("No audio found in " + dir);
Platform.exit();
return;
}
// create a view to show the mediaplayers.
final MediaView mediaView = new MediaView(players.get(0));
final Button skip = new Button("Skip");
final Button play = new Button("Pause");
// play each audio file in turn.
for (int i = 0; i < players.size(); i++) {
final MediaPlayer player = players.get(i);
final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
player.setOnEndOfMedia(new Runnable() {
@Override public void run() {
player.currentTimeProperty().removeListener(progressChangeListener);
player.getMedia().getMetadata().removeListener(metadataChangeListener);
player.stop();
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.play();
}
});
}
// allow the user to skip a track.
skip.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
final MediaPlayer curPlayer = mediaView.getMediaPlayer();
curPlayer.currentTimeProperty().removeListener(progressChangeListener);
curPlayer.getMedia().getMetadata().removeListener(metadataChangeListener);
curPlayer.stop();
MediaPlayer nextPlayer = players.get((players.indexOf(curPlayer) + 1) % players.size());
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.play();
}
});
// allow the user to play or pause a track.
play.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
if ("Pause".equals(play.getText())) {
mediaView.getMediaPlayer().pause();
play.setText("Play");
} else {
mediaView.getMediaPlayer().play();
play.setText("Pause");
}
}
});
// display the name of the currently playing track.
mediaView.mediaPlayerProperty().addListener(new ChangeListener<MediaPlayer>() {
@Override public void changed(ObservableValue<? extends MediaPlayer> observableValue, MediaPlayer oldPlayer, MediaPlayer newPlayer) {
setCurrentlyPlaying(newPlayer);
}
});
// start playing the first track.
mediaView.setMediaPlayer(players.get(0));
mediaView.getMediaPlayer().play();
setCurrentlyPlaying(mediaView.getMediaPlayer());
// silly invisible button used as a template to get the actual preferred size of the Pause button.
Button invisiblePause = new Button("Pause");
invisiblePause.setVisible(false);
play.prefHeightProperty().bind(invisiblePause.heightProperty());
play.prefWidthProperty().bind(invisiblePause.widthProperty());
// add a metadataTable for meta data display
metadataTable.setStyle("-fx-font-size: 13px;");
TableColumn<Map, String> tagColumn = new TableColumn<>(TAG_COLUMN_NAME);
tagColumn.setPrefWidth(150);
TableColumn<Map, Object> valueColumn = new TableColumn<>(VALUE_COLUMN_NAME);
valueColumn.setPrefWidth(400);
tagColumn.setCellValueFactory(new MapValueFactory<>(TAG_COLUMN_NAME));
valueColumn.setCellValueFactory(new MapValueFactory<>(VALUE_COLUMN_NAME));
metadataTable.setEditable(true);
metadataTable.getSelectionModel().setCellSelectionEnabled(true);
metadataTable.getColumns().setAll(tagColumn, valueColumn);
valueColumn.setCellFactory(new Callback<TableColumn<Map, Object>, TableCell<Map, Object>>() {
@Override
public TableCell<Map, Object> call(TableColumn<Map, Object> column) {
return new TableCell<Map, Object>() {
@Override
protected void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
if (item instanceof String) {
setText((String) item);
setGraphic(null);
} else if (item instanceof Integer) {
setText(Integer.toString((Integer) item));
setGraphic(null);
} else if (item instanceof Image) {
setText(null);
ImageView imageView = new ImageView((Image) item);
imageView.setFitWidth(200);
imageView.setPreserveRatio(true);
setGraphic(imageView);
} else {
setText("N/A");
setGraphic(null);
}
} else {
setText(null);
setGraphic(null);
}
}
};
}
});
// layout the scene.
final StackPane layout = new StackPane();
layout.setStyle("-fx-background-color: cornsilk; -fx-font-size: 20; -fx-padding: 20; -fx-alignment: center;");
final HBox progressReport = new HBox(10);
progressReport.setAlignment(Pos.CENTER);
progressReport.getChildren().setAll(skip, play, progress, mediaView);
final VBox content = new VBox(10);
content.getChildren().setAll(
currentlyPlaying,
progressReport,
metadataTable
);
layout.getChildren().addAll(
invisiblePause,
content
);
progress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(progress, Priority.ALWAYS);
VBox.setVgrow(metadataTable, Priority.ALWAYS);
Scene scene = new Scene(layout, 600, 400);
stage.setScene(scene);
stage.show();
}
/** sets the currently playing label to the label of the new media player and updates the progress monitor. */
private void setCurrentlyPlaying(final MediaPlayer newPlayer) {
newPlayer.seek(Duration.ZERO);
progress.setProgress(0);
progressChangeListener = new ChangeListener<Duration>() {
@Override public void changed(ObservableValue<? extends Duration> observableValue, Duration oldValue, Duration newValue) {
progress.setProgress(1.0 * newPlayer.getCurrentTime().toMillis() / newPlayer.getTotalDuration().toMillis());
}
};
newPlayer.currentTimeProperty().addListener(progressChangeListener);
String source = newPlayer.getMedia().getSource();
source = source.substring(0, source.length() - FILE_EXTENSION_LEN);
source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " ");
currentlyPlaying.setText("Now Playing: " + source);
setMetaDataDisplay(newPlayer.getMedia().getMetadata());
}
private void setMetaDataDisplay(ObservableMap<String, Object> metadata) {
metadataTable.getItems().setAll(convertMetadataToTableData(metadata));
metadataChangeListener = new MapChangeListener<String, Object>() {
@Override
public void onChanged(Change<? extends String, ?> change) {
metadataTable.getItems().setAll(convertMetadataToTableData(metadata));
}
};
metadata.addListener(metadataChangeListener);
}
private ObservableList<Map> convertMetadataToTableData(ObservableMap<String, Object> metadata) {
ObservableList<Map> allData = FXCollections.observableArrayList();
for (String key: metadata.keySet()) {
Map<String, Object> dataRow = new HashMap<>();
dataRow.put(TAG_COLUMN_NAME, key);
dataRow.put(VALUE_COLUMN_NAME, metadata.get(key));
allData.add(dataRow);
}
return allData;
}
/** @return a MediaPlayer for the given source which will report any errors it encounters */
private MediaPlayer createPlayer(String mediaSource) {
final Media media = new Media(mediaSource);
final MediaPlayer player = new MediaPlayer(media);
player.setOnError(new Runnable() {
@Override public void run() {
System.out.println("Media error occurred: " + player.getError());
}
});
return player;
}
}
@jewelsea

This comment has been minimized.

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Jun 11, 2013

Answer to StackOverflow question: Java Music Player: Song information and playing

@ryam4u

This comment has been minimized.

Copy link

@ryam4u ryam4u commented Nov 10, 2014

How do I can do AudioClip play sequentially? .. Example audio1 then audio2, etc ..
not find it anywhere 😢

@zemike

This comment has been minimized.

Copy link

@zemike zemike commented Dec 10, 2014

ryam4u, AudioClips are more for one-shot things, as I understood. I had to switch to MediaPlayers for such functionality. (They have setOnEndOfMedia().)

@tywinlannister81093

This comment has been minimized.

Copy link

@tywinlannister81093 tywinlannister81093 commented Feb 9, 2015

how to play a list of audio from url's i.e online link !!!! plzz urgent

@zwaldeck

This comment has been minimized.

Copy link

@zwaldeck zwaldeck commented Jul 27, 2015

Well you load in every audiofile in the directory, And you create a mediaplayer for every one. Thats a performance issue, In example if you have 5000 songs, it would suck up ram, I tested it with visualVM and 927 songs, My ram usage was 225Mb, If you do that times 5 for 5000 songs you almost at 1GB

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Jul 28, 2015

Yes, zwaldeck, if you want to play a large number of files, then you should adjust the algorithm. Feel free to fork the gist to create a version which scales better.

@DylKid

This comment has been minimized.

Copy link

@DylKid DylKid commented Aug 29, 2015

Hey, nice work. I'm trying to write a function that plays an ArrayList of MediaPlayer objects, and I want it to loop the playlist but I can't get it to work. I have tried your code

// play each audio file in turn.
for (int i = 0; i < players.size(); i++) {
final MediaPlayer player = players.get(i);
final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
player.setOnEndOfMedia(new Runnable() {
@override public void run() {
player.currentTimeProperty().removeListener(progressChangeListener);
player.getMedia().getMetadata().removeListener(metadataChangeListener);
player.stop();
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.play();
}
});
}

but it doesn't seem to play anything Could you explain what's going on with
player.currentTimeProperty().removeListener(progressChangeListener); and
player.getMedia().getMetadata().removeListener(metadataChangeListener);

@Fishnchips654

This comment has been minimized.

Copy link

@Fishnchips654 Fishnchips654 commented Dec 19, 2016

i copy pasted the code but it shows me "Exception in thread "main" java.lang.ClassNotFoundException: sample.Main", does anyone have this problem and/or a solution for it?

@amitmishraftp

This comment has been minimized.

Copy link

@amitmishraftp amitmishraftp commented Mar 3, 2017

Hey Dear,
In this Class there is a problem.
While repeat all songs, progressbar is not updating.
So can you please fix this issue.

@Tsyklop

This comment has been minimized.

Copy link

@Tsyklop Tsyklop commented Oct 2, 2018

Hello. This code may produce memory leak:

for (int i = 0; i < players.size(); i++) {
      final MediaPlayer player     = players.get(i);
      final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
      player.setOnEndOfMedia(new Runnable() {
        @Override public void run() {
          player.currentTimeProperty().removeListener(progressChangeListener);
          mediaView.setMediaPlayer(nextPlayer);
          nextPlayer.play();
        }
      });
    }

Here recursive call. I tested and when i press "Skip" button app memory is go up on 1-6 MB and not clear.

@newtingz

This comment has been minimized.

Copy link

@newtingz newtingz commented Sep 25, 2020

hey can someone quite well versed help me on my java project has to do with listview..
and creating custom objects but now im failing to have my clicked file on listview from an observable list play
my email of your willing to help
ii.ss.aac85@gmail.com
thanks

@newtingz

This comment has been minimized.

Copy link

@newtingz newtingz commented Sep 25, 2020

hey can someone quite well versed help me on my java project has to do with listview..
and creating custom objects but now im failing to have my clicked file on listview from an observable list play
my email of your willing to help
ii.ss.aac85@gmail.com
thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.