Skip to content

Commit

Permalink
PlatformPlayer: Handle looping in a different way.
Browse files Browse the repository at this point in the history
Neither MIDI nor WAV threw END_OF_MEDIA events once a loop was
completed. And because of that, neither was the STARTED event. So
now we don't actually set the loop count on the Sequencer and Clip
objects, instead the looping is managed by the metaEventListener
and LineListener added to the media once it's started, as it can
have access to notifying the player listener accordingly.

Sonic 1 Part One requires this in order to loop the invincibility
song and handle the game over transition correctly.

Hopefully, this won't break anything else.
  • Loading branch information
AShiningRay committed Dec 9, 2024
1 parent e8b5ad9 commit f375963
Showing 1 changed file with 25 additions and 15 deletions.
40 changes: 25 additions & 15 deletions src/org/recompile/mobile/PlatformPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ private class midiPlayer extends audioplayer
{
private Sequencer midi;
private Sequence midiSequence;
private int numLoops = 0;

public midiPlayer() // For when a Locator call (usually for tones) is issued
{
Expand Down Expand Up @@ -487,6 +488,12 @@ public void meta(MetaMessage meta)
{
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
}
}
}
});
Expand Down Expand Up @@ -517,8 +524,8 @@ public void setLoopCount(int count)
* it appears that count = 1 means no loop at all, at least based
* on Gameloft games that set effects and some music with count = 1
*/
if(count == Clip.LOOP_CONTINUOUSLY) { midi.setLoopCount(count); }
else { midi.setLoopCount(count-1); }
if(count == Clip.LOOP_CONTINUOUSLY) { numLoops = count; }
else { numLoops = count-1; }
}

public long setMediaTime(long now)
Expand Down Expand Up @@ -574,6 +581,7 @@ private class wavPlayer extends audioplayer
private AudioInputStream wavStream;
private Clip wavClip;
private int[] wavHeaderData = new int[4];
private int numLoops = 0;

public wavPlayer(InputStream stream)
{
Expand Down Expand Up @@ -640,8 +648,14 @@ public void update(LineEvent event)
{
if (event.getType() == LineEvent.Type.STOP)
{
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
}
}
}
});
Expand Down Expand Up @@ -675,8 +689,8 @@ public void setLoopCount(int count)
* it appears that count = 1 means no loop at all, at least based
* on Gameloft games that set effects and some music with count = 1
*/
if(count == Clip.LOOP_CONTINUOUSLY) { wavClip.loop(count); }
else { wavClip.loop(count-1); }
if(count == Clip.LOOP_CONTINUOUSLY) { numLoops = count; }
else { numLoops = count-1; }
}

public long setMediaTime(long now)
Expand Down Expand Up @@ -757,18 +771,14 @@ public void start()

if (!Thread.currentThread().isInterrupted())
{
if(mp3Player.getLoopCount() > 0)
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(mp3Player.getLoopCount() != 0)
{
while(mp3Player.getLoopCount() > 0)
{
mp3Player.decreaseLoopCount();
mp3Player.reset();
mp3Player.play();
}
if(mp3Player.getLoopCount() > 0) { mp3Player.decreaseLoopCount(); } // If getLoopCount() = -1, we're looping indefinitely
mp3Player.reset();
mp3Player.play();
}
// After all loops (if any) are done, notify END_OF_MEDIA
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
state = Player.PREFETCHED;
}
}
catch (Exception e) { Mobile.log(Mobile.LOG_ERROR, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Couldn't start mpeg player:" + e.getMessage()); }
Expand Down

0 comments on commit f375963

Please sign in to comment.