I'm working on a music player and I want to make it so that if I'm playing a song and I click on another song in the list the first song stops before I hit play on the second one, without having to manually stop the first. So just the act of clicking on another song will stop a currently playing song. The following is the code I have so far (I've left out the code for the GUI, just the relevant classes).

public class Player
{
    private PlayList playList;
    private Track track;
    private int tracksPlayed;
    private int totalTrackTime;
    private double averageTrackTime;

    /**
     * Constructor ...
     */
    public Player()
    {
        playList = new PlayList("audio");
        track = null;
        this.tracksPlayed = tracksPlayed;
        this.totalTrackTime = totalTrackTime;
        this.averageTrackTime = averageTrackTime;
    }
    
    /**
     * Return the track collection currently loaded in this player.
     */
    public PlayList getPlayList()
    {
        return playList;
    }
    
    /**
     * Plays the currently selected song
     */
    public void play()
    {
        track.rewind();
        track.play();
        tracksPlayed++;
        int trackDuration = track.getDuration();
        totalTrackTime = totalTrackTime + trackDuration;
        averageTrackTime = totalTrackTime / tracksPlayed;
    }
    
    /**
     * Stops the currently selected song
     */
    public void stop()
    {
        track.stop();
    }
    
    /**
     * Changes the currently selected song
     * @param indicates which track number in the index to change to
     */
    public void setTrack(int trackNumber)
    {
        int currentTrack = trackNumber;
        track = playList.getTrack(currentTrack);
    }
    
    /**
     * Returns the name of the currently selected track
     */
    public String getTrackName()
    {
        String currentTrack = track.getName();
        return currentTrack;
    }

    /**
     * Return information about the currently selected track. The information
     * contains the track name and playing time, in the format
     *    track-name (playing time)
     * Return an empty string if no track is selected.
     */
    public String getTrackInfo()
    {
        String currentTrack = track.getName();
        int trackDuration = track.getDuration();
        return currentTrack + " " + "(" + trackDuration + ")";
    }
    
    /**
     * Returns the total number of tracks played
     */
    public int getNumberOfTracksPlayed()
    {
        return tracksPlayed;
    }
    
    /**
     * Returns the total length of all tracks played combined
     */
    public int getTotalPlayedTrackLength()
    {
        return totalTrackTime;
    }
    
    /**
     * Returns the average length of all tracks played
     */
    public double averageTrackLength()
    {
        return averageTrackTime;
    }
}
public class Track
{
    private Clip soundClip;
    private String name;
    /**
     * Create a track from an audio file.
     */
    public Track(File soundFile)
    {
        soundClip = loadSound(soundFile);
        name = soundFile.getName();
    }

    /**
     * Play this sound track. (The sound will play asynchronously, until 
     * it is stopped or reaches the end.)
     */
    public void play()
    {
        if(soundClip != null) {
            soundClip.start();
        }
    }

    /**
     * Stop this track playing. (This method has no effect if the track is not
     * currently playing.)
     */
    public void stop()
    {
        if(soundClip != null) {
            soundClip.stop();
        }
    }

    /**
     * Reset this track to its start.
     */
    public void rewind()
    {
        if(soundClip != null) {
            soundClip.setFramePosition(0);
        }
    }
        
    /**
     * Return the name of this track.
     */
    public String getName()
    {
        return name;
    }
    
    /**
     * Return the duration of this track, in seconds.
     */
    public int getDuration()
    {
        if (soundClip == null) {
            return 0;
        }
        else {
            return (int) soundClip.getMicrosecondLength()/1000000;
        }
    }
    
    /**
     * Set the playback volume of the current track.
     * 
     * @param vol  Volume level as a percentage (0..100).
     */
    public void setVolume(int vol)
    {
        if(soundClip == null) {
            return;
        }
        if(vol < 0 || vol > 100) {
            vol = 100;
        }

        double val = vol / 100.0;

        try {
            FloatControl volControl =
              (FloatControl) soundClip.getControl(FloatControl.Type.MASTER_GAIN);
            float dB = (float)(Math.log(val == 0.0 ? 0.0001 : val) / Math.log(10.0) * 20.0);
            volControl.setValue(dB);
        } catch (Exception ex) {
            System.err.println("Error: could not set volume");
        }
    }

    /**
     * Return true if this track has successfully loaded and can be played.
     */
    public boolean isValid()
    {
        return soundClip != null;
    }
    
    /**
     * Load the sound file supplied by the parameter.
     * 
     * @return  The sound clip if successful, null if the file could not be decoded.
     */
    private Clip loadSound(File file) 
    {
        Clip newClip;

        try {
            AudioInputStream stream = AudioSystem.getAudioInputStream(file);
            AudioFormat format = stream.getFormat();

            // we cannot play ALAW/ULAW, so we convert them to PCM
            //
            if ((format.getEncoding() == AudioFormat.Encoding.ULAW) ||
                (format.getEncoding() == AudioFormat.Encoding.ALAW)) 
            {
                AudioFormat tmp = new AudioFormat(
                                          AudioFormat.Encoding.PCM_SIGNED, 
                                          format.getSampleRate(),
                                          format.getSampleSizeInBits() * 2,
                                          format.getChannels(),
                                          format.getFrameSize() * 2,
                                          format.getFrameRate(),
                                          true);
                stream = AudioSystem.getAudioInputStream(tmp, stream);
                format = tmp;
            }
            DataLine.Info info = new DataLine.Info(Clip.class, 
                                           stream.getFormat(),
                                           ((int) stream.getFrameLength() *
                                           format.getFrameSize()));

            newClip = (Clip) AudioSystem.getLine(info);
            newClip.open(stream);
            return newClip;
        } catch (Exception ex) {
            return null;
        }
    }
}
public class PlayList
{
    private List<Track> tracks; 
    
    /**
     * Constructor for objects of class TrackCollection
     */
    public PlayList(String directoryName)
    {
        tracks = loadTracks(directoryName);
    }
    
    /**
     * Return a track from this collection.
     */
    public Track getTrack(int trackNumber)
    {
        return tracks.get(trackNumber);
    }

    /**
     * Return the number of tracks in this collection.
     */
    public int numberOfTracks()
    {
        return tracks.size();
    }
    
    /**
     * Load the file names of all files in the given directory.
     * @param dirName Directory (folder) name.
     * @param suffix File suffix of interest.
     * @return The names of files found.
     */
    private List<Track> loadTracks(String dirName)
    {
        File dir = new File(dirName);
        if(dir.isDirectory()) {
            File[] allFiles = dir.listFiles();
            List<Track> foundTracks = new ArrayList<Track>();

            for(File file : allFiles) {
                //System.out.println("found: " + file);
                Track track = new Track(file);
                if(track.isValid()) {
                    foundTracks.add(track);
                }
            }
            return foundTracks;
        }
        else {
            System.err.println("Error: " + dirName + " must be a directory");
            return null;
        }
    }

    /**
     * Return this playlist as an array of strings with the track names.
     */
    public String[] asStrings()
    {
        String[] names = new String[tracks.size()];
        int i = 0;
        for(Track track : tracks) {
            names[i++] = track.getName();
        }
        return names;
    }
}

I have tried just about everything I can think of. I have tried to initiate the stop method before the play method, however that doesn't work because the track has already been changed and therefore does not affect the current track. So I figure I have to use a variable to store the current track. However, I have tried multiple combinations of both local and field variables and I can't seem to get it to work right. Any help would be much appreciated.

Recommended Answers

All 2 Replies

call stop before changing the track.

Wow, thanks! I kept looking at the solution as a manipulation of the play method, when it actually a simple line to add to the setTrack method. I figured it would be an easy solution that I would kick myself when it was solved. Now I feel ashamed. :(

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.