-
Notifications
You must be signed in to change notification settings - Fork 4
Music Player (JukeBox)
The music player can play music from a playlist, fade in/out and switch between different playlists as they are played. MusicPlayer would be a perfect name for it, yet I decided against it and called the whole thing JukeBox
. This is not because I think it fits better, but rather to avoid confusion with the word Music in libGDX. In libGDX Music simply stands for a streaming sound source. In that sense, a music player would just be a unit that plays said source.
Class | Description |
---|---|
JukeBox | This is the music player, it needs to be updated every frame and offers methods to play Song s from PlayList s. |
JukeBoxObserver | If you want to be informed about status changes of the JukeBox , you can implement this interface and register as observer of the JukeBox. Classic observer design pattern. |
PlayList | A PlayList is a collection of any number of Song s that should be grouped together. The JukeBox plays them in order. |
PlayListProvider | The PlayListProvider is responsible for providing the JukeBox with PlayList s. If a PlayList was played completely, the JukeBox asks the PlayListProvider for the next PlayList . This is an interface, the implementation is entirely up to you. However, there are built-in implementations for the most common use cases. |
Song | A Song groups a SoundSource , SoundSettings and SongMeta . |
SongSettings | Contains settings how a Song should be played. For example, the volume can be specified here or the fade-in and fade-out configuration. |
SongMeta | In the SongMeta information about a Song can be stored, such as artist, track name, album... this is totally optional though! |
Here's an example of how these classes play together: JukeBoxTest
So let's start with creating a Song
we can put in a PlayList
later on. SongMeta
and SongSettings
are optional but let's create both to see what's possible. The SoundSource
might be a BufferedSoundSource
or a StreamedSoundSource
, that's up to you.
SongMeta meta = new SongMeta().setTitle("Learning To Fly").setArtist("Tom Petty");
SongSettings settings = SongSettings.linear(volume, fadeInDuration, fadeOutDuration);
Song song = new Song(soundSource, settings, meta);
// optional: If you want to play the Song globally, don't forget to make the SoundSource relative.
soundSource.setRelative(true);
In case you are wondering how this system prevents the SoundSource
from being modified while in use by the JukeBox
...
It is not prevented.
The responsibility is on you to leave the source alone. At the same time this is freedom and gives you more possibilities to change the sound with effects or the like.
A list of songs, loopable, shuffleable and that's it. Let's create one and add our Song
to it:
PlayList playList = new PlayList();
playList.setLooping(true);
playList.setShuffleAfterPlaytrough(true);
playList.addSong(song1);
playList.addSong(song2);
playList.addSong(song3);
Now we have a PlayList
containing three songs, it's shuffled after each playthrough and it will be played in a loop.
Though, it will only be looped if the PlayListProvider
does not provide another PlayList
when the JukeBox
asks for one.
A PlayListProvider
provides the JukeBox
with PlayLists
. It's an interface with just 2 methods: hasNext()
and next()
.
It's up to the implementation how PlayList
s are returned by next()
. So feel free to create your own implmentation that fits your needs.
There's built-in implementations for the most common use cases:
Class | Description |
---|---|
DefaultPlayListProvider | This class holds just a list of PlayList s and provides them in order. When all PlayList s got fetched by next() , playback stops. |
CircularPlayListProvider | The same as DefaultPlayListProvider but fetched PlayList s won't be removed and playback will start again with the first PlayList when the last one finished playing. |
ThemePlayListProvider | This provider provides PlayList s based on a theme. The theme might be any integer ID you chose. The player is in a boss fight? Set the theme to boss fight and the boss music PlayList will be provided. The player wins the boss fight? Set the theme back to normal. |
PlayListProvider provider = new DefaultPlayListProvider().add(playList1).add(playList2);
And finally let's create a JukeBox
, start playback and update it properly:
private JukeBox jukeBox = new JukeBox(provider);
jukeBox.play();
// somewhere in libGDX's render loop
@Override
public void render() {
jukeBox.update();
}
Besides pausing and stopping the JukeBox
, there's also a softStop()
method that allows for fading out the Song
before stopping:
jukeBox.softStop(Interpolation.linear, fadeOutDuration);
And last but not least, if you want to be notified when a Song
finished playing or if a new Song
or PlayList
starts, register as an observer:
JukeBoxObserver observer = new MyObserver();
jukeBox.addObserver(observer);
public class MyObserver implements JukeBoxObserver {
@Override
public void onSongStart(Song song) {
System.out.println("Song started: " + song.getMeta().getTitle());
}
@Override
public void onSongEnd(Song song) {
System.out.println("Song ended: " + song.getMeta().getTitle());
}
@Override
public void onPlayListStart(PlayList playList) {
System.out.println("PlayList started: " + playList);
}
@Override
public void onPlayListEnd(PlayList playList) {
System.out.println("PlayList ended: " + playList);
}
@Override
public void onJukeBoxEnd() {
System.out.println("JukeBox ended");
}
@Override
public void onJukeBoxStart() {
System.out.println("JukeBox started");
}
@Override
public void onJukeBoxPause() {
System.out.println("JukeBox paused");
}
}