Object-oriented design - pause function - java

I was trying to sharp my OOD thinking. Here is my question.
Suppose you want to design a music mp3 player. And I got a class with a collection of playlists.
class Player {
Map<String, List<Song>> playlists; // <Name, PlayList>
public void play (Song song) {
// decode song
// play song
}
public void play (String playlistName) {
// play a playlist
for (Song song : playlists.get(playlistName)) {
play (song);
}
}
public void stop () {
// stop playing
}
public void pause () {
// pause, resume playing the last song when hit play again
}
}
Let's assume "Song" already contains all the metadata of a song. All the functionalities of methods have been described. I got stucked when I was trying to realize the "pause" method. What would you do to realize this?
Thanks!

Look into state pattern. Which you will store state of the player. When you hit pause and play you will know the state of the player.

I would have a Song member variable that tracks the currently playing song. If there is nothing playing, the value would be set to null. When you pause a Song, you simply call the Pause method on the Song class if the currently playing Song is not null. The Song class in turn can track where in the song (in terms of minutes) it is and figure out how a resume would work.

It seems to me like th play method blocks until the song has finished. It is a completely single-threaded design. When you design your application like that, it can't react to user input while a song is playing (unless you place an input handler into the playing loop).
In a real-world application, the play() method would start playing the song in a separate thread (many audio APIs will do that for you, so that you don't have to mingle with multi-threading) and then return, so that the application can stay responsible while a song is playing.
That way the pause and resume methods would then interact with the thread which plays the song.

Related

How can I fix my audio? (Prioritize)

When two audio's are played at the same time...the sound is canceling out. How do I fix this weird phenomenon?
I have some code where there is audio on button click and audio in ten second intervals (in a background service). I have the following code to stop the button audio when the ten second interval plays, and it works fine:
public static void myPop(Context context){
AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
if(!manager.isMusicActive()) { //Only if there isn't any other audio playing
MediaPlayer pop = MediaPlayer.create(context, R.raw.pop);
pop.start();
}
else{
Log.v(TAG, "Audio is already playing");
}
}
This works fine, and it stops one audio from playing (pop) to let the other audio play(The one from the background service). Now, I am getting the issue when they both play at the same time. For example, when I tap the button at the exact same time as when the audio from the background service is about to start. when they are both played at the same time, the audio just gets cut off
Is there any way to give a preference to the background service audio? Somehow say that: If two audio pieces start at the exact same time, I want to let the background service audio to play.
To think of this visually:
(https://upload.wikimedia.org/wikipedia/en/4/49/Preference_example.jpg)
I want to say that if I have the choice between apples and oranges, pick apples. AKA If I have two audioplayers playing at the same time, pick one (the apple).
Thanks for your help,
Ruchir
You may have a race condition. In these three lines
1 if(!manager.isMusicActive()) {
2 MediaPlayer pop = MediaPlayer.create(context, R.raw.pop);
3 pop.start();
Between line 1 and line 3, there is opportunity for another player to get the media player and start playing, especially if line 2 is slow.
I would suggest making one media player that both players access (i.e. create the "MediaPlayer pop" elsewhere and share it), or find another way to synchronize the different players. Perhaps issuing a stop right before a play, rather than checking for play state.
You can use code for play or pause audio when other player start or pause.
AudioManager.OnAudioFocusChangeListener afChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};
For more referernce
http://developer.android.com/training/managing-audio/audio-focus.html

Android - info for create a loop pad - music app

I want to create a music loop pad, something like this: https://www.youtube.com/watch?v=fwBPYwiYp-Y
Right now, i am using MediaPlayer to play the sounds. I have a global variable that stores the current time (position) of the first audio that is playing, and when i press another button the corresponding audio file starts playing at the position given by the global variable.
My proble is: the sounds are playing out of sync.
can you give me some help? How can i sync the sounds? like this app https://www.youtube.com/watch?v=fwBPYwiYp-Y
Can you point me some info or tutorials about how to create a loop pad?
Thanks
Richardd
Programming something like this is harder than you think. Here are two things you must do to have the sounds play in sync:
Make sure all you sounds are at the same tempo, and are cropped properly - that means that the starting and ending of the sound clip must be exactly on beat - another solution would be to store the starting and ending time for each clip (very easy with OOP)
Use a timer to make sure the sound starts playing on beat. For example, if you wanted to make your music run at 120 bpm, you would need to have your timer fire every 500 ms.
Here is some code (only concept, won't compile):
Timer beatTimer;
boolean isDrumLoopEnabled;
boolean isDrumLoopCurrentlyPlaying;
Sound drumloop;
public void startMusic(){
//prepare timer
beatTimer=new Timer();
beatTimer.interval=500;//for 120 bpm
beatTimer.onTick+=onTickHandler;
isDrumLoopPlaying=false;
isDrumLoopCurrentlyPlaying=false;
//load sounds
Sound drumloop=new Sound("/storage/emulated/drumloop.ogg");
//start music
beatTiemr.start();
}
//this method will run on every beat:
public void onTickHandler(){
if(isDrumLoopEnabled){
//make sure drum loop isn't already playing
if(!isDrumLoopCurrentlyPlaying){
//begin looping drumloop in background
drumloop.startloop();
isDrumLoopCurrentlyPlaying=true;
}
}else{
if(isDrumLoopCurrentlyPlaying){
//stop playing drumloop
drumloop.stopPlaying();
}
}
}
//when the button is pressed...
public void drumloop_buttonpressed(){
//this will toggle whether to play the drum loop:
isDrumLoopEnabled=!isDrumLoopEnabled;
}

Kill Overlapping Threads from Intent in Android mp3 app

I am having a problem (I think) with overlapping threads playing music in my android mp3 player. I have a class SongList.java that lists and plays music when an item is clicked and a ArtistList.java that intents SongList to play songs by that specific artist. Two or more songs will play at the same time if they are not in the same activity.
How do I tell my playSong method to stop all threads but the most recent one?
You should have just one single Thread or service doing playback.
SongList and ArtistList should not start a new service. Rather you should have a PlaybackService you can pass a SongList or ArtistList as parameter / argument. If doing so, you should just have one single Thread doing playback and never run into that kind of trouble.
Have a look here:
http://developer.android.com/guide/topics/media/mediaplayer.html#mpandservices
They implement a Service that uses the build in MediaPlayer for audio playback. Next you can bind your MusicPlaybackService to an activity.
Here is an introduction:
http://developer.android.com/guide/components/bound-services.html
You can specify methods that the activity can invoke on your service with the help of Binder. So you could provide a method like playSongs(SongList songs) or playArtists(ArtistList list) that could be invoked by the activity (i.e. by clicking on a certain button). Since the service runs the playback (by using MediaPlayer) the service is responsible for Threading and playback. So if you call playSongs(SongList songs) of the service, the Service should stop MediaPlayer and restart MediaPlayer with the desired music file (provided by SongList). With this approach your MusicPlaybackService manages the playback and guarantees that only one music file is played simultaneously.

Why can I stop a Sound in a Screen's hide event but am I unable to pause it? LIBGDX

I'm using LIBGDX for my gamedev. I'm using com.badglogic.gdx.audio.Sound for my game sounds. I have a weird problem in my game screen . If I press the HOME button of my phone to exit the game and I Sound.stop the sound in the hide event of the game screen then when I re-enter the game I don't hear the sound anymore and that is what is supposed to happen. But if I instead use the Sound.pause method (instead of stop) then I hear the sound when I re-enter the game instance.
Why does Sound.stop work and Sound.pause doesn't?
PS: I've removed all the Sound.resume method instances from my code that would possible create such behavior.
works:
#Override
public void hide(){
spaceship_sound.stop(id_spaceship_sound);
}
doesn't work:
#Override
public void hide(){
spaceship_sound.pause(id_spaceship_sound);
}
I've even put the pause method in the keyDown (HOME button) and pause game screen events, practically all over the code with no luck.

How to know when a song is finished playing?

I am working on a small sound player which plays songs. I am using the TinySound library https://github.com/finnkuusisto/TinySound. And as I can see from the API, it does come with a method called .done() which tells me wheter a Music object is finished playing or not, but how can I test for it while playing?
I have currently created a JFrame with buttons and a Jlist which displays the songs, but I understand that if I try some sort of while loop to listen for wheter or not the song is finished I wont be able to use the other buttons such as stop, pause etc.
I was thinking somewhere along this line (pseudo code):
while(theSong.playing()){
if(theSong.done()){
playNext();
}
}
The problem is that when entering the while loop, I am not able to use any other functions in my program. If anyone wants to see some sample code, please let me know!
Sindre M
Running this while on the same thread as your GUI will make the interface stuck. You can achieve the desired functionality using SwingUtilities invokeAndWait method:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
while(theSong.playing()) {
if(theSong.done()) {
playNext();
}
}
}
}

Categories

Resources