3 Replies Latest reply: Jul 16, 2012 11:05 AM by JohnHendrikx RSS

    Get the duration of all mp3 files inside a directory

    587523
      Hello everyone,

      I am working on a little project done with swing. Since I need an mp3 player inside my swing application, I found a really good solution with JavaFX 2. I have never worked with JavaFX before, therefor it seems to me a little bit strange on some parts.
      Anyway.

      I created a button on my application and as soon as somebody presses that button, the application should scan recursivly a unique directory for mp3 files and store the information of artist, title and track length into a database.

      The mp3 player I created is based on the example from this page:
      http://www.java2s.com/Code/Java/JavaFX/Mp3playerwithmetadataviewandcontrolpanel.htm

      I understand the source code for most parts, but some behaivors are not really clear to me. My thoughts about getting the complete length of the mp3 file was

      media.getDuration
      or
      mediaplayer.getTotalDuration

      but both results are NaN if I call .toMillis();

      Instead I need to create a listener (why?)
      private class TotalDurationListener implements InvalidationListener {
          @Override
          public void invalidated(Observable observable) {
            final MediaPlayer mediaPlayer = songModel.getMediaPlayer();
            final Duration totalDuration = mediaPlayer.getTotalDuration();
            totalDurationLabel.setText(formatDuration(totalDuration));
          }
        }
      and register this listener on the mediaplayer
      mp.totalDurationProperty().addListener(new TotalDurationListener());
      I can image that the mediaplayer can "host" several media objects somewho and the listener is called as soon as a new media will be added to the mediaplayer in order
      the calculate the overall duration.

      When is this listener exactly called and is there no other ways to get the total length of the mp3 file?


      Here is a minimal example which should work without any external libs

      package de.hauke.schwimmbad.application.playground;
      
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.io.File;
      import java.util.ArrayList;
      import java.util.List;
      
      import javafx.application.Platform;
      import javafx.beans.property.ReadOnlyObjectWrapper;
      import javafx.embed.swing.JFXPanel;
      import javafx.scene.Scene;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.media.Media;
      import javafx.scene.media.MediaPlayer;
      import javafx.scene.paint.Color;
      import javafx.util.Duration;
      
      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.UIManager;
      
      public class Testing10 extends JFrame {
      
           private MediaPlayer mediaPlayer;
      
           private final ReadOnlyObjectWrapper<MediaPlayer> mediaPlayerWrapper = new ReadOnlyObjectWrapper<MediaPlayer>(
                     this, "mediaPlayer");
           
           public static void main(String[] args) {
                try {
                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                     new Testing10();
                } catch (Exception ex) {
                     System.out.println(ex);
                }
           }
           
           public Testing10() {
                super();
      
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
                setLayout(null);
                setSize(500, 500);
                setTitle("Testing");
      
                setLocationRelativeTo(null);
                setResizable(false);
      
                JButton button = new JButton("Scan");
                button.setBounds(10, 10, 150, 30);
                add(button);
                button.addActionListener(new ActionListener() {
      
                     public void actionPerformed(ActionEvent arg0) {
                          scan();
                     }
                });
      
                final JFXPanel fxPanel = new JFXPanel();
                fxPanel.setBounds(30, 80, 300, 300);
                add(fxPanel);
      
                Platform.runLater(new Runnable() {
                     public void run() {
                          initFX(fxPanel);
                     }
                });
                setVisible(true);
           }
      
           
           
           
           private void scan() {
                File directory = new File("C:\\dev\\mp3");
                List<File> mp3Files = new ArrayList<File>();
                
                for (File file : directory.listFiles()) {
                     if(file.getName().endsWith("mp3")) {
                          mp3Files.add(file);
                     }
                }
                
                for (File file : mp3Files) {
                     System.out.println(file.getAbsoluteFile());
                     getLength(file);
                }
           }
           
      
           private Duration getLength(File file) {
                if(mediaPlayer != null) {
                     mediaPlayer.stop();
                }
                
                final Media media = new Media(file.toURI().toString());
                 
                mediaPlayer = new MediaPlayer(media);
                mediaPlayerWrapper.setValue(mediaPlayer);
                
                if(media.durationProperty()==null) System.out.println("durationProperty ist null");
                if(media.durationProperty().get()==null) System.out.println(".get() ist null");
                System.out.println("---> " + media.durationProperty().get().toMillis());
                
                return media.getDuration();
           }
           
           
           private void initFX(JFXPanel fxPanel) {
                BorderPane root = new BorderPane();
                Scene scene = new Scene(root, Color.ALICEBLUE);
                fxPanel.setScene(scene);
           }
      }
      The other question is why do I need a listener for the meta data to be changed in order to get the meta data?
      media.getMetadata().addListener(new MapChangeListener<String, Object>()
      Why can't I call something like
      media.getMetadata() --> returns a filled map?

      The metadata problem is not included inside the example from above.


      Sorry for my english but I hope everybody can understand the issue.

      Many greetings,
      Hauke
        • 1. Re: Get the duration of all mp3 files inside a directory
          JohnHendrikx
          The nature of the Media class is that it accesses it asynchronously. This means that when you create an instance of it, and then immediately query it, the data you want may not be available yet. This is all in the Javadoc, see the doc for Media:
          The media information is obtained asynchronously and so not necessarily available immediately after instantiation of the class. All information should however be available if the instance has been associated with a MediaPlayer and that player has transitioned to MediaPlayer.Status.READY status
          So you could associate the Media with a MediaPlayer, and then wait until it goes to the Status READY, and then read the length of the Media.

          As for your 2nd question, getMetadata() returns a Map. You can just loop through it:
            for(Map.Entry<String, Object> entry : media.getMetadata()) {
              // etc
            }
          However, the same restrictions apply as with Media -- you will probably need to wait before the information is available -- that's why the Listener approach works, because it will notify you as soon as the information is added to the map.
          • 2. Re: Get the duration of all mp3 files inside a directory
            587523
            Hi,

            thanks for your reply. That helped a lot. Now I am doing this
                      while(mediaPlayer.getStatus() != Status.READY) {
                           Thread.sleep(10);
                      }
            and its works.

            Great and thanks for your help. I've worked with the status before in order to display the play or pause button, but I didn't recognized the READY state. Is there a better way then to put the thread to sleep? Isn't there a callback method? Well it's working, but I am just interested.

            Greetings,
            Hauke
            • 3. Re: Get the duration of all mp3 files inside a directory
              JohnHendrikx
              Hm, I've not really used the MediaPlayer before, but wouldn't you be able to simply listen to the status change with a ChangeListener instead of a sleep?

              Something like this (didn't check if it compiles):
              mediaPlayer.statusProperty().addListener(new ChangeListener<Status>() {
                public void changed(Observable o, Status old, Status current) {
                  if(current == Status.READY) {
                     // check length...
                  }
                }
              });