first commit

This commit is contained in:
Boris
2024-01-15 20:14:10 +00:00
commit 8c81ee28b7
3106 changed files with 474415 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
#BlueJ class context
comment0.params=filename
comment0.target=MusicFilePlayer(java.lang.String)
comment0.text=\n\ Creates\ a\ new\ MusicFilePlayer\ instance.\n\ @param\ filename\ The\ file\ to\ be\ played.\n
comment1.params=
comment1.target=void\ play()
comment1.text=\n\ Play\ the\ whole\ file.\n
comment10.params=
comment10.target=int\ getFrameNumber()
comment10.text=\n\ Return\ the\ current\ frame\ number.\n\ @return\ The\ number\ of\ the\ last\ frame\ played,\ or\ -1\ if\ nothing\ played\ yet.\n
comment11.params=start\ end
comment11.target=boolean\ playFrames(int,\ int)
comment11.text=\n\ Play\ the\ number\ of\ frames\ left.\n\ @return\ true\ If\ finished\ for\ any\ reason,\ false\ if\ paused.\n
comment12.params=position
comment12.target=void\ moveTo(int)
comment12.text=\n\ Set\ the\ playing\ position.\n\ @param\ position\ (in\ frames)\n
comment13.params=
comment13.target=void\ close()
comment13.text=\n\ Cloases\ this\ player.\ Any\ audio\ currently\ playing\ is\ stopped\n\ immediately.\n
comment14.params=
comment14.target=boolean\ decodeFrame()
comment14.text=\n\ Decodes\ a\ single\ frame.\n\n\ @return\ true\ if\ there\ are\ no\ more\ frames\ to\ decode,\ false\ otherwise.\n
comment15.params=
comment15.target=boolean\ skipFrame()
comment15.text=\n\ skips\ over\ a\ single\ frame\n\ @return\ false\ \ \ \ if\ there\ are\ no\ more\ frames\ to\ decode,\ true\ otherwise.\n
comment16.params=
comment16.target=void\ stop()
comment16.text=\n\ closes\ the\ player\ and\ notifies\ <code>PlaybackListener</code>\n
comment17.params=filename
comment17.target=int\ getFrameCount(java.lang.String)
comment17.text=\n\ Count\ the\ number\ of\ frames\ in\ the\ file.\n\ This\ can\ be\ used\ for\ positioning.\n\ @param\ filename\ The\ file\ to\ be\ measured.\n\ @return\ The\ number\ of\ frames.\n
comment18.params=
comment18.target=javazoom.jl.decoder.Header\ readFrame()
comment18.text=\n\ Read\ a\ frame.\n\ @return\ The\ frame\ read.\n
comment19.params=
comment19.target=void\ openAudio()
comment19.text=\n\ Open\ an\ audio\ device.\n
comment2.params=frames
comment2.target=boolean\ play(int)
comment2.text=\n\ Plays\ a\ number\ of\ MPEG\ audio\ frames.\n\n\ @param\ frames\ \ \ \ The\ number\ of\ frames\ to\ play.\n\ @return\ \ true\ if\ the\ last\ frame\ was\ played,\ or\ false\ if\ there\ are\n\ \ \ \ \ \ \ \ \ \ more\ frames.\n
comment20.params=filename
comment20.target=void\ openBitstream(java.lang.String)
comment20.text=\n\ Open\ a\ BitStream\ for\ the\ given\ file.\n\ @param\ filename\ The\ file\ to\ be\ opened.\n\ @throws\ IOException\ If\ the\ file\ cannot\ be\ opened.\n
comment3.params=start\ end
comment3.target=boolean\ play(int,\ int)
comment3.text=\n\ Plays\ a\ range\ of\ MPEG\ audio\ frames\n\ @param\ start\ The\ first\ frame\ to\ play\n\ @param\ end\ \ \ \ \ \ \ The\ last\ frame\ to\ play\n\ @return\ true\ if\ the\ last\ frame\ was\ played,\ or\ false\ if\ there\ are\ more\ frames.\n
comment4.params=start
comment4.target=boolean\ playFrom(int)
comment4.text=\n\ Play\ from\ the\ given\ position\ to\ the\ end.\n\ @param\ start\ The\ first\ frame\ to\ play.\n\ @return\ true\ if\ the\ last\ frame\ was\ played,\ or\ false\ if\ there\ are\ more\ frames.\n
comment5.params=
comment5.target=int\ getLength()
comment5.text=\n\ Get\ the\ length\ of\ the\ file\ (in\ frames).\n\ @return\ The\ file\ length,\ in\ frames.\n
comment6.params=
comment6.target=int\ getPosition()
comment6.text=\n\ Get\ the\ current\ playing\ position\ (in\ frames).\n\ @return\ The\ current\ frame\ number.\n
comment7.params=position
comment7.target=void\ setPosition(int)
comment7.text=\n\ Set\ the\ playing\ position\ (in\ frames).\n\ Playing\ does\ not\ start\ until\ resume()\ is\ called.\n\ @param\ position\ The\ playing\ position.\n
comment8.params=
comment8.target=void\ pause()
comment8.text=\n\ Pause\ the\ playing.\n
comment9.params=
comment9.target=void\ resume()
comment9.text=\n\ Resume\ the\ playing.\n
numComments=21

View File

@@ -0,0 +1,413 @@
/**
* 11/19/04 1.0 moved to LGPL.
*-----------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*----------------------------------------------------------------------
*/
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.BitstreamException;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.Header;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.decoder.SampleBuffer;
import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.FactoryRegistry;
/**
* Play music files.
* This class is a modified version of javazoom.jl.player.advanced.AdvancedPlayer,
* which is part of the javazoom JLayer library.
* The main modifications consist of:
* + Restriction to playing files rather than streams.
* + Pre-reading of the audio file to determine its length in frames.
* These modifications permit arbitrary seek operations.
*
* Modifications by David J. Barnes and Michael Kölling.
* @version 2016.02.29
* This class is not suitable for playing streams as a file is read
* completely before playing.
*/
public class MusicFilePlayer
{
// The MPEG audio bitstream.
private Bitstream bitstream;
// The MPEG audio decoder.
private Decoder decoder;
// The AudioDevice the audio samples are written to.
private AudioDevice audio;
// Whether currently playing.
private boolean playing = false;
// The file being played.
private String filename;
// The number of frames.
private int frameCount;
// The current frame number.
private int frameNumber;
// The position to resume, if any.
private int resumePosition;
/**
* Creates a new MusicFilePlayer instance.
* @param filename The file to be played.
*/
public MusicFilePlayer(String filename) throws JavaLayerException
{
this.filename = filename;
openAudio();
frameCount = getFrameCount(filename);
// Open a fresh bitstream following the frame count.
openBitstream(filename);
frameNumber = 0;
resumePosition = -1;
}
/**
* Play the whole file.
*/
public void play() throws JavaLayerException
{
playFrames(0, frameCount);
}
/**
* Plays a number of MPEG audio frames.
*
* @param frames The number of frames to play.
* @return true if the last frame was played, or false if there are
* more frames.
*/
public boolean play(int frames) throws JavaLayerException
{
return playFrames(frameNumber, frameNumber + frames);
}
/**
* Plays a range of MPEG audio frames
* @param start The first frame to play
* @param end The last frame to play
* @return true if the last frame was played, or false if there are more frames.
*/
public boolean play(int start, int end) throws JavaLayerException
{
return playFrames(start, start + end);
}
/**
* Play from the given position to the end.
* @param start The first frame to play.
* @return true if the last frame was played, or false if there are more frames.
*/
public boolean playFrom(int start) throws JavaLayerException
{
return playFrames(start, frameCount);
}
/**
* Get the length of the file (in frames).
* @return The file length, in frames.
*/
public int getLength()
{
return frameCount;
}
/**
* Get the current playing position (in frames).
* @return The current frame number.
*/
public int getPosition()
{
return frameNumber;
}
/**
* Set the playing position (in frames).
* Playing does not start until resume() is called.
* @param position The playing position.
*/
public void setPosition(int position) throws JavaLayerException
{
pause();
resumePosition = position;
}
/**
* Pause the playing.
*/
public void pause() throws JavaLayerException
{
synchronized(this) {
playing = false;
resumePosition = frameNumber;
}
}
/**
* Resume the playing.
*/
public void resume() throws JavaLayerException
{
if(!playing) {
int start;
if(resumePosition >= 0) {
start = resumePosition;
}
else {
start = frameNumber;
}
resumePosition = -1;
playFrames(start, frameCount);
}
}
/**
* Return the current frame number.
* @return The number of the last frame played, or -1 if nothing played yet.
*/
public int getFrameNumber()
{
return frameNumber;
}
/**
* Play the number of frames left.
* @return true If finished for any reason, false if paused.
*/
private boolean playFrames(int start, int end) throws JavaLayerException
{
// Clear any resumption position.
resumePosition = -1;
if(end > frameCount) {
end = frameCount;
}
// Make sure the player is in the correct position in the input.
synchronized(this) {
moveTo(start);
playing = true;
}
// Play until finished, paused, or a problem.
boolean ok = true;
while (frameNumber < end && playing && ok) {
ok = decodeFrame();
if(ok) {
frameNumber++;
}
}
// Stopped for some reason.
synchronized(this) {
playing = false;
// last frame, ensure all data flushed to the audio device.
AudioDevice out = audio;
if (out != null) {
out.flush();
}
}
return ok;
}
/**
* Set the playing position.
* @param position (in frames)
*/
private void moveTo(int position) throws JavaLayerException
{
if(position < frameNumber) {
synchronized(this) {
// Already played too far.
if(bitstream != null) {
try {
bitstream.close();
}
catch (BitstreamException ex) {
}
}
if(audio != null) {
audio.close();
}
openAudio();
openBitstream(filename);
frameNumber = 0;
}
}
while(frameNumber < position) {
skipFrame();
frameNumber++;
}
}
/**
* Cloases this player. Any audio currently playing is stopped
* immediately.
*/
public void close()
{
synchronized(this) {
if (audio != null) {
AudioDevice out = audio;
audio = null;
// this may fail, so ensure object state is set up before
// calling this method.
out.close();
try {
bitstream.close();
}
catch (BitstreamException ex) {
}
bitstream = null;
decoder = null;
}
}
}
/**
* Decodes a single frame.
*
* @return true if there are no more frames to decode, false otherwise.
*/
protected boolean decodeFrame() throws JavaLayerException
{
try
{
synchronized (this) {
if (audio == null) {
return false;
}
Header h = readFrame();
if (h == null) {
return false;
}
// sample buffer set when decoder constructed
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);
if(audio != null) {
audio.write(output.getBuffer(), 0, output.getBufferLength());
}
}
bitstream.closeFrame();
}
catch (RuntimeException ex) {
ex.printStackTrace();
throw new JavaLayerException("Exception decoding audio frame", ex);
}
return true;
}
/**
* skips over a single frame
* @return false if there are no more frames to decode, true otherwise.
*/
protected boolean skipFrame() throws JavaLayerException
{
Header h = readFrame();
if (h == null) {
return false;
}
frameNumber++;
bitstream.closeFrame();
return true;
}
/**
* closes the player and notifies <code>PlaybackListener</code>
*/
public void stop()
{
close();
}
/**
* Count the number of frames in the file.
* This can be used for positioning.
* @param filename The file to be measured.
* @return The number of frames.
*/
protected int getFrameCount(String filename) throws JavaLayerException
{
openBitstream(filename);
int count = 0;
while(skipFrame()) {
count++;
}
bitstream.close();
return count;
}
/**
* Read a frame.
* @return The frame read.
*/
protected Header readFrame() throws JavaLayerException
{
if(audio != null) {
return bitstream.readFrame();
}
else {
return null;
}
}
/**
* Open an audio device.
*/
protected void openAudio() throws JavaLayerException
{
audio = FactoryRegistry.systemRegistry().createAudioDevice();
decoder = new Decoder();
audio.open(decoder);
}
/**
* Open a BitStream for the given file.
* @param filename The file to be opened.
* @throws IOException If the file cannot be opened.
*/
protected void openBitstream(String filename)
throws JavaLayerException
{
try {
bitstream = new Bitstream(new BufferedInputStream(
new FileInputStream(filename)));
}
catch(java.io.IOException ex) {
throw new JavaLayerException(ex.getMessage(), ex);
}
}
}

View File

@@ -0,0 +1,42 @@
#BlueJ class context
comment0.params=folderName
comment0.target=MusicOrganizer(java.lang.String)
comment0.text=\n\ Create\ a\ MusicOrganizer.\n\ @param\ folderName\ The\ folder\ of\ audio\ files.\n
comment1.params=filename
comment1.target=void\ addFile(java.lang.String)
comment1.text=\n\ Add\ a\ track\ file\ to\ the\ collection.\n\ @param\ filename\ The\ file\ name\ of\ the\ track\ to\ be\ added.\n
comment10.params=t1\ t2
comment10.target=int\ compare(Track,\ Track)
comment11.params=index
comment11.target=void\ removeTrack(int)
comment11.text=\n\ Remove\ a\ track\ from\ the\ collection.\n\ @param\ index\ The\ index\ of\ the\ track\ to\ be\ removed.\n
comment12.params=index
comment12.target=boolean\ indexValid(int)
comment12.text=\n\ Determine\ whether\ the\ given\ index\ is\ valid\ for\ the\ collection.\n\ Print\ an\ error\ message\ if\ it\ is\ not.\n\ @param\ index\ The\ index\ to\ be\ checked.\n\ @return\ true\ if\ the\ index\ is\ valid,\ false\ otherwise.\n
comment13.params=folderName
comment13.target=void\ readLibrary(java.lang.String)
comment2.params=track
comment2.target=void\ addTrack(Track)
comment2.text=\n\ Add\ a\ track\ to\ the\ collection.\n\ @param\ track\ The\ track\ to\ be\ added.\n
comment3.params=index
comment3.target=Track\ getTrack(int)
comment3.text=\n\ Get\ a\ track\ from\ the\ collection.\n\ @param\ index\ The\ index\ of\ the\ track.\n\ @return\ The\ selected\ track,\ or\ null\ if\ it\ does\ not\ exist.\n
comment4.params=
comment4.target=int\ getNumberOfTracks()
comment4.text=\n\ Return\ the\ number\ of\ tracks\ in\ the\ collection.\n\ @return\ The\ number\ of\ tracks\ in\ the\ collection.\n
comment5.params=
comment5.target=java.util.List\ getAllTracks()
comment5.text=\n\ Return\ a\ copy\ of\ all\ the\ tracks\ in\ the\ collection.\n\ @return\ All\ the\ tracks\ in\ the\ collection.\n
comment6.params=
comment6.target=java.util.List\ sortByArtist()
comment6.text=\n\ Return\ a\ list\ of\ the\ tracks,\ sorted\ by\ artist.\n\ @return\ The\ tracks,\ sorted\ by\ artist.\n
comment7.params=
comment7.target=java.util.List\ sortByTitle()
comment7.text=\n\ Return\ a\ list\ of\ the\ tracks,\ sorted\ by\ title.\n\ @return\ The\ tracks,\ sorted\ by\ title.\n
comment8.params=comparator
comment8.target=java.util.List\ sortBy(java.util.Comparator)
comment8.text=\n\ Return\ a\ sorted\ copy\ of\ the\ track\ list.\n\ @param\ comparator\ The\ comparator\ for\ the\ sort.\n\ @return\ A\ sorted\ copy\ of\ the\ list.\n
comment9.params=field
comment9.target=java.util.List\ sortByField(java.lang.String)
comment9.text=\n\ Return\ a\ list\ of\ the\ tracks,\ sorted\ by\ the\ given\ field\ name.\n\ @param\ field\ The\ field\ to\ sort\ by;\ e.g.,\ Artist,\ Title,\ etc.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ @see\ Track.FIELDS\n\ @return\ The\ tracks,\ sorted\ by\ the\ field.\n
numComments=14

View File

@@ -0,0 +1,174 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* A class to hold details of audio tracks.
* Individual tracks may be played.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class MusicOrganizer
{
// An ArrayList for storing music tracks.
private ArrayList<Track> tracks;
// A reader that can read music files and load them as tracks.
private TrackReader reader;
/**
* Create a MusicOrganizer.
* @param folderName The folder of audio files.
*/
public MusicOrganizer(String folderName)
{
tracks = new ArrayList<>();
reader = new TrackReader();
readLibrary(folderName);
}
/**
* Add a track file to the collection.
* @param filename The file name of the track to be added.
*/
public void addFile(String filename)
{
tracks.add(new Track(filename));
}
/**
* Add a track to the collection.
* @param track The track to be added.
*/
public void addTrack(Track track)
{
tracks.add(track);
}
/**
* Get a track from the collection.
* @param index The index of the track.
* @return The selected track, or null if it does not exist.
*/
public Track getTrack(int index)
{
if(indexValid(index)) {
return tracks.get(index);
}
else {
return null;
}
}
/**
* Return the number of tracks in the collection.
* @return The number of tracks in the collection.
*/
public int getNumberOfTracks()
{
return tracks.size();
}
/**
* Return a copy of all the tracks in the collection.
* @return All the tracks in the collection.
*/
public List<Track> getAllTracks()
{
return new ArrayList<>(tracks);
}
/**
* Return a list of the tracks, sorted by artist.
* @return The tracks, sorted by artist.
*/
public List<Track> sortByArtist()
{
return sortByField("Artist");
}
/**
* Return a list of the tracks, sorted by title.
* @return The tracks, sorted by title.
*/
public List<Track> sortByTitle()
{
return sortByField("Field");
}
/**
* Return a sorted copy of the track list.
* @param comparator The comparator for the sort.
* @return A sorted copy of the list.
*/
private List<Track> sortBy(Comparator<Track> comparator)
{
List<Track> copy = getAllTracks();
Collections.sort(copy, comparator);
return copy;
}
/**
* Return a list of the tracks, sorted by the given field name.
* @param field The field to sort by; e.g., Artist, Title, etc.
* @see Track.FIELDS
* @return The tracks, sorted by the field.
*/
public List<Track> sortByField(final String field)
{
return sortBy(new Comparator<Track>() {
public int compare(Track t1, Track t2)
{
return t1.getField(field).compareTo(t2.getField(field));
}
});
}
/**
* Remove a track from the collection.
* @param index The index of the track to be removed.
*/
public void removeTrack(int index)
{
if(indexValid(index)) {
tracks.remove(index);
}
}
/**
* Determine whether the given index is valid for the collection.
* Print an error message if it is not.
* @param index The index to be checked.
* @return true if the index is valid, false otherwise.
*/
private boolean indexValid(int index)
{
// The return value.
// Set according to whether the index is valid or not.
boolean valid;
if(index < 0) {
System.out.println("Index cannot be negative: " + index);
valid = false;
}
else if(index >= tracks.size()) {
System.out.println("Index is too large: " + index);
valid = false;
}
else {
valid = true;
}
return valid;
}
public void readLibrary(String folderName)
{
ArrayList<Track> tempTracks = reader.readTracks(folderName, ".mp3");
// Put all thetracks into the organizer.
for(Track track : tempTracks) {
addTrack(track);
}
}
}

View File

@@ -0,0 +1,39 @@
#BlueJ class context
comment0.params=
comment0.target=MusicPlayer()
comment0.text=\n\ Constructor\ for\ objects\ of\ class\ MusicPlayer\n
comment1.params=filename
comment1.target=void\ startPlaying(java.lang.String)
comment1.text=\n\ Start\ playing\ the\ given\ audio\ file.\n\ The\ method\ returns\ once\ the\ playing\ has\ been\ started.\n\ @param\ filename\ The\ file\ to\ be\ played.\n
comment10.params=
comment10.target=void\ run()
comment11.params=
comment11.target=void\ killPlayer()
comment11.text=\n\ Terminate\ the\ player,\ if\ there\ is\ one.\n
comment12.params=
comment12.target=void\ reportProblem()
comment12.text=\n\ Report\ a\ problem\ playing\ the\ current\ file.\n
comment2.params=
comment2.target=void\ stop()
comment2.text=\n\ Stop\ playing\ the\ current\ file.\n
comment3.params=
comment3.target=void\ pause()
comment3.text=\n\ Pause\ the\ current\ file.\n
comment4.params=
comment4.target=void\ resume()
comment4.text=\n\ Resume\ playing\ following\ a\ pause.\n
comment5.params=
comment5.target=void\ run()
comment6.params=position
comment6.target=void\ seekTo(int)
comment6.text=\n\ Seek\ to\ the\ given\ position\ in\ the\ current\ file.\n\ The\ track\ will\ be\ paused\ as\ a\ result\ of\ this\ operation.\n\ \n\ @param\ position\ What\ position\ in\ the\ file\ to\ move\ to.\n
comment7.params=
comment7.target=int\ getLength()
comment7.text=\n\ Return\ the\ length\ of\ the\ current\ music\ file,\ if\ any.\n\ The\ length\ is\ in\ 'frames'\ rather\ than\ seconds,\ for\ instance.\n\ \n\ @return\ The\ file\ length\ in\ frames.\n
comment8.params=filename
comment8.target=void\ setupPlayer(java.lang.String)
comment8.text=\n\ Set\ up\ the\ player\ ready\ to\ play\ the\ given\ file.\n\ @param\ filename\ The\ name\ of\ the\ file\ to\ play.\n
comment9.params=start
comment9.target=void\ playFrom(int)
comment9.text=\n\ Play\ from\ the\ given\ position.\n\ @param\ start\ The\ starting\ position\ for\ playing.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Must\ be\ within\ the\ current\ file's\ length.\n
numComments=13

View File

@@ -0,0 +1,191 @@
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.FactoryRegistry;
/**
* Provide basic playing of MP3 files via the javazoom library.
* See http://www.javazoom.net/
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class MusicPlayer
{
// The current player. It might be null.
private MusicFilePlayer player;
// The current file being played.
private String filename;
/**
* Constructor for objects of class MusicPlayer
*/
public MusicPlayer()
{
player = null;
filename = "";
}
/**
* Start playing the given audio file.
* The method returns once the playing has been started.
* @param filename The file to be played.
*/
public void startPlaying(final String filename)
{
try {
setupPlayer(filename);
playFrom(0);
}
catch (JavaLayerException ex) {
reportProblem();
}
}
/**
* Stop playing the current file.
*/
public void stop()
{
killPlayer();
}
/**
* Pause the current file.
*/
public void pause()
{
if(player != null) {
try {
player.pause();
}
catch(JavaLayerException e) {
reportProblem();
killPlayer();
}
}
}
/**
* Resume playing following a pause.
*/
public void resume()
{
if(player != null) {
Thread playerThread = new Thread() {
public void run()
{
try {
player.resume();
}
catch(JavaLayerException e) {
reportProblem();
killPlayer();
}
}
};
playerThread.setPriority(Thread.MIN_PRIORITY);
playerThread.start();
}
}
/**
* Seek to the given position in the current file.
* The track will be paused as a result of this operation.
*
* @param position What position in the file to move to.
*/
public void seekTo(int position)
{
if(player != null && position >= 0 && position < player.getLength()) {
// Set the player's position.
}
}
/**
* Return the length of the current music file, if any.
* The length is in 'frames' rather than seconds, for instance.
*
* @return The file length in frames.
*/
public int getLength()
{
if(player != null) {
return player.getLength();
}
else {
return 0;
}
}
/**
* Set up the player ready to play the given file.
* @param filename The name of the file to play.
*/
private void setupPlayer(String filename)
{
try {
if(player != null) {
killPlayer();
}
this.filename = filename;
player = new MusicFilePlayer(filename);
}
catch(JavaLayerException e) {
System.out.println("Problem setting up player");
e.printStackTrace();
reportProblem();
killPlayer();
}
}
/**
* Play from the given position.
* @param start The starting position for playing.
* Must be within the current file's length.
*/
private void playFrom(final int start) throws JavaLayerException
{
Thread playerThread = new Thread() {
public void run()
{
try {
player.playFrom(start);
}
catch(JavaLayerException e) {
reportProblem();
killPlayer();
}
}
};
playerThread.setPriority(Thread.MIN_PRIORITY);
playerThread.start();
}
/**
* Terminate the player, if there is one.
*/
private void killPlayer()
{
synchronized(this) {
if(player != null) {
player.stop();
player = null;
filename = "";
}
}
}
/**
* Report a problem playing the current file.
*/
private void reportProblem()
{
System.out.println("There was a problem playing: " + filename);
}
}

View File

@@ -0,0 +1,41 @@
#BlueJ class context
comment0.params=args
comment0.target=void\ main(java.lang.String[])
comment0.text=\n\ Main\ method\ for\ starting\ the\ player\ from\ a\ command\ line.\n
comment1.params=
comment1.target=MusicPlayerGUI()
comment1.text=\n\ Create\ a\ SoundPlayer\ and\ display\ its\ GUI\ on\ screen.\n
comment10.params=trackList
comment10.target=java.lang.String[]\ getTracksDisplayList(java.util.List)
comment10.text=\n\ Get\ a\ display\ version\ of\ the\ track\ list.\n\ @param\ trackList\ The\ list\ of\ tracks\ to\ be\ displayed.\n\ @return\ The\ tracks\ in\ display\ format.\n
comment11.params=
comment11.target=void\ makeFrame()
comment11.text=\n\ Create\ the\ complete\ application\ GUI.\n
comment12.params=
comment12.target=void\ makeMenuBar()
comment12.text=\n\ Create\ the\ main\ frame's\ menu\ bar.\n
comment2.params=
comment2.target=void\ play()
comment2.text=\n\ Play\ the\ sound\ file\ currently\ selected\ in\ the\ file\ list.\ If\ there\ is\ no\n\ selection\ in\ the\ list,\ or\ if\ the\ selected\ file\ is\ not\ a\ sound\ file,\ \n\ do\ nothing.\n
comment3.params=
comment3.target=void\ stop()
comment3.text=\n\ Stop\ the\ currently\ playing\ sound\ file\ (if\ there\ is\ one\ playing).\n
comment4.params=
comment4.target=void\ pause()
comment4.text=\n\ Stop\ the\ currently\ playing\ sound\ file\ (if\ there\ is\ one\ playing).\n
comment5.params=
comment5.target=void\ resume()
comment5.text=\n\ Resume\ a\ previously\ suspended\ sound\ file.\n
comment6.params=message
comment6.target=void\ showInfo(java.lang.String)
comment6.text=\n\ Display\ information\ about\ a\ selected\ sound\ file\ (name\ and\ clip\ length).\n\ @param\ message\ The\ message\ to\ display.\n
comment7.params=
comment7.target=void\ quit()
comment7.text=\n\ Quit\ function\:\ quit\ the\ application.\n
comment8.params=
comment8.target=void\ showAbout()
comment8.text=\n\ About\ function\:\ show\ the\ 'about'\ box.\n
comment9.params=ordering
comment9.target=void\ setListOrdering(java.lang.String)
comment9.text=\n\ Set\ the\ ordering\ of\ the\ track\ list.\n\ @param\ ordering\ The\ ordering\ to\ use.\n
numComments=13

View File

@@ -0,0 +1,308 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.io.*;
/**
* A simple sound player. To start, create an instance of this class.
*
* The sound player provides an interface to the MusicOrganizer class
* from chapter 4.
*
* @author Michael Kölling and David J. Barnes
* @version 1.0
*/
public class MusicPlayerGUI extends JFrame
{
private static final String VERSION = "Version 1.0";
private static final String AUDIO_DIR = "../audio";
private JList<String> fileList;
private JSlider slider;
private JLabel infoLabel;
private MusicOrganizer organizer;
// A player for the music tracks.
private MusicPlayer player;
// The current track list.
private List<Track> trackList;
/**
* Main method for starting the player from a command line.
*/
public static void main(String[] args)
{
MusicPlayerGUI gui = new MusicPlayerGUI();
}
/**
* Create a SoundPlayer and display its GUI on screen.
*/
public MusicPlayerGUI()
{
super("Music Player");
organizer = new MusicOrganizer(AUDIO_DIR);
player = new MusicPlayer();
makeFrame();
}
/**
* Play the sound file currently selected in the file list. If there is no
* selection in the list, or if the selected file is not a sound file,
* do nothing.
*/
private void play()
{
int index = fileList.getSelectedIndex();
if(index >= 0 && index < trackList.size()) {
slider.setValue(0);
player.startPlaying(trackList.get(index).getFilename());
}
}
/**
* Stop the currently playing sound file (if there is one playing).
*/
private void stop()
{
player.stop();
}
/**
* Stop the currently playing sound file (if there is one playing).
*/
private void pause()
{
player.pause();
}
/**
* Resume a previously suspended sound file.
*/
private void resume()
{
player.resume();
}
/**
* Display information about a selected sound file (name and clip length).
* @param message The message to display.
*/
private void showInfo(String message)
{
infoLabel.setText(message);
}
/**
* Quit function: quit the application.
*/
private void quit()
{
System.exit(0);
}
/**
* About function: show the 'about' box.
*/
private void showAbout()
{
JOptionPane.showMessageDialog(this,
"Music Player\n" + VERSION,
"About Music Player",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Set the ordering of the track list.
* @param ordering The ordering to use.
*/
private void setListOrdering(String ordering)
{
trackList = organizer.sortByField(ordering);
String[] tracks = getTracksDisplayList(trackList);
fileList.setListData(tracks);
}
/**
* Get a display version of the track list.
* @param trackList The list of tracks to be displayed.
* @return The tracks in display format.
*/
private String[] getTracksDisplayList(List<Track> trackList)
{
int numTracks = trackList.size();
String[] tracks = new String[numTracks];
for(int i = 0; i < numTracks; i++) {
String[] fields = trackList.get(i).getFields();
StringBuilder listing = new StringBuilder();
for(String field : fields) {
listing.append(field);
listing.append(" ");
}
tracks[i] = listing.toString().trim();
}
return tracks;
}
// ---- Swing stuff to build the frame and all its components and menus ----
/**
* Create the complete application GUI.
*/
private void makeFrame()
{
// the following makes sure that our application exits when
// the user closes its window
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel contentPane = (JPanel) getContentPane();
contentPane.setBorder(new EmptyBorder(6, 10, 10, 10));
makeMenuBar();
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(8, 8));
// Create the left side with combobox and scroll list
JPanel leftPane = new JPanel();
{
leftPane.setLayout(new BorderLayout(8, 8));
// Set up components for ordering the list of tracks.
JPanel orderingPanel = new JPanel();
orderingPanel.setLayout(new BorderLayout());
orderingPanel.add(new JLabel("Order by:"), BorderLayout.NORTH);
// Get the list of field names, used for ordering.
String[] ordering = Track.FIELDS;
// Create the combo box.
JComboBox<String> formatList = new JComboBox<>(ordering);
formatList.addActionListener(e -> {
int index = formatList.getSelectedIndex();
if(index >= 0) {
String selectedOrder = formatList.getItemAt(index);
setListOrdering(selectedOrder);
}
});
orderingPanel.add(formatList, BorderLayout.CENTER);
leftPane.add(orderingPanel, BorderLayout.NORTH);
// Create the scrolled list for track listing.
fileList = new JList<>();
fileList.setForeground(new Color(140,171,226));
fileList.setBackground(new Color(0,0,0));
fileList.setSelectionBackground(new Color(87,49,134));
fileList.setSelectionForeground(new Color(140,171,226));
JScrollPane scrollPane = new JScrollPane(fileList);
scrollPane.setColumnHeaderView(new JLabel("Audio files"));
leftPane.add(scrollPane, BorderLayout.CENTER);
// Set up the initial listing.
setListOrdering(ordering[0]);
}
contentPane.add(leftPane, BorderLayout.CENTER);
// Create the center with image, text label, and slider
JPanel centerPane = new JPanel();
{
centerPane.setLayout(new BorderLayout(8, 8));
JLabel image = new JLabel(new ImageIcon("title.jpg"));
centerPane.add(image, BorderLayout.NORTH);
centerPane.setBackground(Color.BLACK);
infoLabel = new JLabel(" ");
infoLabel.setHorizontalAlignment(SwingConstants.CENTER);
infoLabel.setForeground(new Color(140,171,226));
centerPane.add(infoLabel, BorderLayout.CENTER);
slider = new JSlider(0, 100, 0);
TitledBorder border = new TitledBorder("Seek");
border.setTitleColor(Color.white);
slider.setBorder(new CompoundBorder(new EmptyBorder(6, 10, 10, 10), border));
// Provide a body for the change-listener lambda to react to changes
// of the slider.
slider.addChangeListener(e -> { });
slider.setBackground(Color.BLACK);
slider.setMajorTickSpacing(25);
slider.setPaintTicks(true);
centerPane.add(slider, BorderLayout.SOUTH);
}
contentPane.add(centerPane, BorderLayout.EAST);
// Create the toolbar with the buttons
JPanel toolbar = new JPanel();
{
toolbar.setLayout(new GridLayout(1, 0));
JButton button = new JButton("Play");
button.addActionListener(e -> play());
toolbar.add(button);
button = new JButton("Stop");
button.addActionListener(e -> stop());
toolbar.add(button);
button = new JButton("Pause");
button.addActionListener(e -> pause());
toolbar.add(button);
button = new JButton("Resume");
button.addActionListener(e -> resume());
toolbar.add(button);
}
contentPane.add(toolbar, BorderLayout.NORTH);
// building is done - arrange the components
pack();
// place this frame at the center of the screen and show
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
setLocation(d.width/2 - getWidth()/2, d.height/2 - getHeight()/2);
setVisible(true);
}
/**
* Create the main frame's menu bar.
*/
private void makeMenuBar()
{
final int SHORTCUT_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
setJMenuBar(menubar);
JMenu menu;
JMenuItem item;
// create the File menu
menu = new JMenu("File");
menubar.add(menu);
item = new JMenuItem("Quit");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
item.addActionListener(e -> quit());
menu.add(item);
// create the Help menu
menu = new JMenu("Help");
menubar.add(menu);
item = new JMenuItem("About Music Player...");
item.addActionListener(e -> showAbout());
menu.add(item);
}
}

View File

@@ -0,0 +1,17 @@
Project: musicplayer. A project to play audio files.
Authors: David J. Barnes and Michael Kölling
This project is part of the material for the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 13.
To start:
Create a MusicPlayerGUI object.
Select a track from the list and play it.

View File

@@ -0,0 +1,29 @@
#BlueJ class context
comment0.params=artist\ title\ filename
comment0.target=Track(java.lang.String,\ java.lang.String,\ java.lang.String)
comment0.text=\n\ Constructor\ for\ objects\ of\ class\ Track.\n\ @param\ artist\ The\ track's\ artist.\n\ @param\ title\ The\ track's\ title.\n\ @param\ filename\ The\ track\ file.\ \n
comment1.params=filename
comment1.target=Track(java.lang.String)
comment1.text=\n\ Constructor\ for\ objects\ of\ class\ Track.\n\ It\ is\ assumed\ that\ the\ file\ name\ cannot\ be\n\ decoded\ to\ extract\ artist\ and\ title\ details.\n\ @param\ filename\ The\ track\ file.\ \n
comment2.params=
comment2.target=java.lang.String\ getArtist()
comment2.text=\n\ Return\ the\ artist.\n\ @return\ The\ artist.\n
comment3.params=
comment3.target=java.lang.String\ getTitle()
comment3.text=\n\ Return\ the\ title.\n\ @return\ The\ title.\n
comment4.params=
comment4.target=java.lang.String\ getFilename()
comment4.text=\n\ Return\ the\ file\ name.\n\ @return\ The\ file\ name.\n
comment5.params=field
comment5.target=java.lang.String\ getField(java.lang.String)
comment5.text=\n\ Return\ the\ value\ of\ the\ named\ field.\n\ The\ field\ should\ be\ an\ element\ of\ Track.FIELDS\n\ @param\ field\ Which\ field\ to\ return.\n
comment6.params=
comment6.target=java.lang.String[]\ getFields()
comment6.text=\n\ Return\ the\ values\ of\ the\ fields.\n\ @return\ The\ fields.\n
comment7.params=
comment7.target=java.lang.String\ getDetails()
comment7.text=\n\ Return\ details\ of\ the\ track\:\ artist,\ title\ and\ file\ name.\n\ @return\ The\ track's\ details.\n
comment8.params=artist\ title\ filename
comment8.target=void\ setDetails(java.lang.String,\ java.lang.String,\ java.lang.String)
comment8.text=\n\ Set\ details\ of\ the\ track.\n\ @param\ artist\ The\ track's\ artist.\n\ @param\ title\ The\ track's\ title.\n\ @param\ filename\ The\ track\ file.\ \n
numComments=9

View File

@@ -0,0 +1,132 @@
/**
* Store the details of a music track,
* such as the artist, title, and file name.
* Use the FIELDS class variable for the names of
* the available attributes.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class Track
{
// The artist.
private String artist;
// The track's title.
private String title;
// Where the track is stored.
private String filename;
// Names for the available fields.
public static final String[] FIELDS = {
"Artist",
"Title",
"Filename",
};
/**
* Constructor for objects of class Track.
* @param artist The track's artist.
* @param title The track's title.
* @param filename The track file.
*/
public Track(String artist, String title, String filename)
{
setDetails(artist, title, filename);
}
/**
* Constructor for objects of class Track.
* It is assumed that the file name cannot be
* decoded to extract artist and title details.
* @param filename The track file.
*/
public Track(String filename)
{
setDetails("unknown", "unknown", filename);
}
/**
* Return the artist.
* @return The artist.
*/
public String getArtist()
{
return artist;
}
/**
* Return the title.
* @return The title.
*/
public String getTitle()
{
return title;
}
/**
* Return the file name.
* @return The file name.
*/
public String getFilename()
{
return filename;
}
/**
* Return the value of the named field.
* The field should be an element of Track.FIELDS
* @param field Which field to return.
*/
public String getField(String field)
{
if (field.equals("Artist")) {
return artist;
}
else if (field.equals("Title")) {
return title;
}
else if (field.equals("Filename")) {
return filename;
}
else {
throw new IllegalArgumentException("Unknown field name: " + field);
}
}
/**
* Return the values of the fields.
* @return The fields.
*/
public String[] getFields()
{
String[] fields = new String[FIELDS.length];
for(int i = 0; i < FIELDS.length; i++) {
fields[i] = getField(FIELDS[i]);
}
return fields;
}
/**
* Return details of the track: artist, title and file name.
* @return The track's details.
*/
public String getDetails()
{
return artist + ": " + title + " (file: " + filename + ")";
}
/**
* Set details of the track.
* @param artist The track's artist.
* @param title The track's title.
* @param filename The track file.
*/
private void setDetails(String artist, String title, String filename)
{
this.artist = artist;
this.title = title;
this.filename = filename;
}
}

View File

@@ -0,0 +1,14 @@
#BlueJ class context
comment0.params=
comment0.target=TrackReader()
comment0.text=\n\ Create\ the\ track\ reader,\ ready\ to\ read\ tracks\ from\ the\ music\ library\ folder.\n
comment1.params=folder\ suffix
comment1.target=java.util.ArrayList\ readTracks(java.lang.String,\ java.lang.String)
comment1.text=\n\ Read\ music\ files\ from\ the\ given\ library\ folder\n\ with\ the\ given\ suffix.\n\ @param\ folder\ The\ folder\ to\ look\ for\ files.\n\ @param\ suffix\ The\ suffix\ of\ the\ audio\ type.\n
comment2.params=dir\ name
comment2.target=boolean\ accept(java.io.File,\ java.lang.String)
comment2.text=\n\ Accept\ files\ with\ matching\ suffix.\n\ @param\ dir\ The\ directory\ containing\ the\ file.\n\ @param\ name\ The\ name\ of\ the\ file.\n\ @return\ true\ if\ the\ name\ ends\ with\ the\ suffix.\n
comment3.params=file
comment3.target=Track\ decodeDetails(java.io.File)
comment3.text=\n\ Try\ to\ decode\ details\ of\ the\ artist\ and\ the\ title\n\ from\ the\ file\ name.\n\ It\ is\ assumed\ that\ the\ details\ are\ in\ the\ form\:\n\ \ \ \ \ artist-title.mp3\n\ @param\ file\ The\ track\ file.\n\ @return\ A\ Track\ containing\ the\ details.\n
numComments=4

View File

@@ -0,0 +1,91 @@
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
/**
* A helper class for our music application. This class can read files from the file system
* from a given folder with a specified suffix. It will interpret the file name as artist/
* track title information.
*
* It is expected that file names of music tracks follow a standard format of artist name
* and track name, separated by a dash. For example: TheBeatles-HereComesTheSun.mp3
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class TrackReader
{
/**
* Create the track reader, ready to read tracks from the music library folder.
*/
public TrackReader()
{
// Nothing to do here.
}
/**
* Read music files from the given library folder
* with the given suffix.
* @param folder The folder to look for files.
* @param suffix The suffix of the audio type.
*/
public ArrayList<Track> readTracks(String folder, final String suffix)
{
File audioFolder = new File(folder);
ArrayList<Track> tracks = new ArrayList<>();
File[] audioFiles = audioFolder.listFiles(new FilenameFilter() {
/**
* Accept files with matching suffix.
* @param dir The directory containing the file.
* @param name The name of the file.
* @return true if the name ends with the suffix.
*/
public boolean accept(File dir, String name)
{
return name.toLowerCase().endsWith(suffix);
}
});
// Put all the matching files into the organizer.
for(File file : audioFiles) {
Track trackDetails = decodeDetails(file);
tracks.add(trackDetails);
}
return tracks;
}
/**
* Try to decode details of the artist and the title
* from the file name.
* It is assumed that the details are in the form:
* artist-title.mp3
* @param file The track file.
* @return A Track containing the details.
*/
private Track decodeDetails(File file)
{
// The information needed.
String artist = "unknown";
String title = "unknown";
String filename = file.getPath();
// Look for artist and title in the name of the file.
String details = file.getName();
String[] parts = details.split("-");
if(parts.length == 2) {
artist = parts[0];
String titlePart = parts[1];
// Remove a file-type suffix.
parts = titlePart.split("\\.");
if(parts.length >= 1) {
title = parts[0];
}
else {
title = titlePart;
}
}
return new Track(artist, title, filename);
}
}

View File

@@ -0,0 +1,115 @@
#BlueJ package file
dependency1.from=MusicOrganizer
dependency1.to=Track
dependency1.type=UsesDependency
dependency2.from=TrackReader
dependency2.to=Track
dependency2.type=UsesDependency
dependency3.from=MusicOrganizer
dependency3.to=TrackReader
dependency3.type=UsesDependency
dependency4.from=MusicPlayerGUI
dependency4.to=MusicOrganizer
dependency4.type=UsesDependency
dependency5.from=MusicPlayerGUI
dependency5.to=MusicPlayer
dependency5.type=UsesDependency
dependency6.from=MusicPlayerGUI
dependency6.to=Track
dependency6.type=UsesDependency
dependency7.from=MusicPlayer
dependency7.to=MusicFilePlayer
dependency7.type=UsesDependency
objectbench.height=76
objectbench.width=842
package.editor.height=487
package.editor.width=734
package.editor.x=70
package.editor.y=80
package.numDependencies=7
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=751
readme.editor.width=1110
readme.editor.x=41
readme.editor.y=49
target1.editor.height=704
target1.editor.width=831
target1.editor.x=41
target1.editor.y=23
target1.height=60
target1.name=MusicPlayerGUI
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=110
target1.x=170
target1.y=30
target2.editor.height=777
target2.editor.width=1112
target2.editor.x=124
target2.editor.y=23
target2.height=60
target2.name=MusicFilePlayer
target2.naviview.expanded=true
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=110
target2.x=160
target2.y=370
target3.editor.height=700
target3.editor.width=930
target3.editor.x=41
target3.editor.y=100
target3.height=60
target3.name=MusicPlayer
target3.naviview.expanded=true
target3.showInterface=false
target3.type=ClassTarget
target3.typeParameters=
target3.width=110
target3.x=50
target3.y=250
target4.editor.height=700
target4.editor.width=900
target4.editor.x=175
target4.editor.y=68
target4.height=60
target4.name=TrackReader
target4.naviview.expanded=true
target4.showInterface=false
target4.type=ClassTarget
target4.typeParameters=
target4.width=110
target4.x=340
target4.y=170
target5.editor.height=777
target5.editor.width=1071
target5.editor.x=209
target5.editor.y=23
target5.height=60
target5.name=MusicOrganizer
target5.naviview.expanded=true
target5.showInterface=false
target5.type=ClassTarget
target5.typeParameters=
target5.width=140
target5.x=530
target5.y=100
target6.editor.height=700
target6.editor.width=900
target6.editor.x=271
target6.editor.y=23
target6.height=60
target6.name=Track
target6.naviview.expanded=true
target6.showInterface=false
target6.type=ClassTarget
target6.typeParameters=
target6.width=110
target6.x=460
target6.y=270

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB