From beebdd406ef9c919db2a631ea9102280c7412c04 Mon Sep 17 00:00:00 2001 From: AShiningRay Date: Mon, 9 Dec 2024 12:59:01 -0300 Subject: [PATCH] PlatformPlayer + Nokia Sound: Make nokia sound player more robust FreeJ2ME now handles get/setGain, and also properly handles SoundListener change events, as well as checking for the player state on play/resume/stop calls. play() is now conformant to the Nokia documentation, which dictates that the media should ALWAYS play from the start here (otherwise it would act like resume()). --- src/com/nokia/mid/sound/Sound.java | 27 +++++++++--- src/org/recompile/mobile/PlatformPlayer.java | 43 ++++++++++++++------ 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/com/nokia/mid/sound/Sound.java b/src/com/nokia/mid/sound/Sound.java index 763afa46..cd8dd8b5 100644 --- a/src/com/nokia/mid/sound/Sound.java +++ b/src/com/nokia/mid/sound/Sound.java @@ -35,6 +35,7 @@ import javax.sound.midi.Track; import org.recompile.mobile.Mobile; +import org.recompile.mobile.PlatformPlayer; /* Using references from http://www.j2megame.org/j2meapi/Nokia_UI_API_1_1/com/nokia/mid/sound/Sound.html */ public class Sound @@ -62,7 +63,6 @@ public class Sound private static final double SEMITONE_CONST = 17.31234049066755; // 1/(ln(2^(1/12))) private Player player; - private SoundListener soundListener; private static int parsePos = 0; // Used exclusively as a marker for OTA/OTT Parsing private static boolean[] toneBitArray; @@ -82,8 +82,6 @@ public class Sound public static int getConcurrentSoundCount(int type) { return 1; } - public int getGain() { return 0; } - public int getState() { int state = player.getState(); @@ -158,19 +156,36 @@ public void init(int freq, long duration) public void play(int loop) { + if(getState() == SOUND_PLAYING) { player.stop(); } + if(getState() == SOUND_UNINITIALIZED) { return; } if(loop < 0) { throw new IllegalArgumentException("Cannot play media, invalid loop value received"); } else if(loop == 0) { loop = -1; } + player.setLoopCount(loop); + player.setMediaTime(0); // A play call always makes the media play from the beginning. player.start(); } public void release() { player.close(); } - public void resume() { player.start(); } + public void resume() + { + if(getState() == SOUND_UNINITIALIZED || getState() == SOUND_PLAYING) { return; } + player.start(); + } - public void setGain(int gain) { } + public void setGain(int gain) + { + // Gain goes from 0 to 255, while setLevel works from 0 to 100 + ((PlatformPlayer.volumeControl)player.getControl("VolumeControl")).setLevel((int) (gain / 255 * 100)); + } + + public int getGain() + { + return (int) ((((PlatformPlayer.volumeControl)player.getControl("VolumeControl")).getLevel() / 100) * 255); + } - public void setSoundListener(SoundListener soundListener) { this.soundListener = soundListener; } + public void setSoundListener(SoundListener soundListener) { ((PlatformPlayer) player).setSoundListener(this, soundListener); } public void stop() { player.stop(); } diff --git a/src/org/recompile/mobile/PlatformPlayer.java b/src/org/recompile/mobile/PlatformPlayer.java index 72926f33..c83e2361 100644 --- a/src/org/recompile/mobile/PlatformPlayer.java +++ b/src/org/recompile/mobile/PlatformPlayer.java @@ -50,6 +50,10 @@ import javax.sound.sampled.FloatControl; import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; + +import com.nokia.mid.sound.Sound; +import com.nokia.mid.sound.SoundListener; + import javax.microedition.media.Player; import javax.microedition.media.PlayerListener; import javax.microedition.media.control.ToneControl; @@ -73,6 +77,9 @@ public class PlatformPlayer implements Player private Vector listeners; + private SoundListener nokiaListener; + private Sound nokiaSound; + private Control[] controls; // Manager already sets these two @@ -257,6 +264,15 @@ public void addPlayerListener(PlayerListener playerListener) listeners.add(playerListener); } + public void setSoundListener(Sound sound, SoundListener listener) // Nokia Sound only has methods to set the Sound Listener, not remove it + { + if(getState() == Player.CLOSED) { throw new IllegalStateException("Cannot add SoundListener to an UNINITIALIZED Sound"); } + if(listener == null) { return; } + + nokiaListener = listener; + nokiaSound = sound; + } + public void removePlayerListener(PlayerListener playerListener) { if(getState() == Player.CLOSED) { throw new IllegalStateException("Cannot remove PlayerListener from a CLOSED player"); } @@ -271,6 +287,13 @@ private void notifyListeners(String event, Object eventData) { listeners.get(i).playerUpdate(this, event, eventData); } + + if(nokiaListener != null) + { + if(event == PlayerListener.CLOSED) { nokiaListener.soundStateChanged(nokiaSound, Sound.SOUND_UNINITIALIZED); } + else if(event == PlayerListener.STARTED) { { nokiaListener.soundStateChanged(nokiaSound, Sound.SOUND_PLAYING); } } + else if(event == PlayerListener.STOPPED || event == PlayerListener.END_OF_MEDIA) { { nokiaListener.soundStateChanged(nokiaSound, Sound.SOUND_STOPPED); } } + } } public void deallocate() @@ -363,14 +386,10 @@ public Control getControl(String controlType) { if(getState() == Player.CLOSED || getState() == Player.UNREALIZED) { throw new IllegalStateException("Cannot call getControl(), as the player is either CLOSED or UNREALIZED."); } - if(controlType.equals("VolumeControl")) { return controls[0]; } - if(controlType.equals("TempoControl")) { return controls[1]; } - if(controlType.equals("MIDIControl")) { return controls[2]; } - if(controlType.equals("ToneControl")) { return controls[3]; } - if(controlType.equals("javax.microedition.media.control.VolumeControl")) { return controls[0]; } - if(controlType.equals("javax.microedition.media.control.TempoControl")) { return controls[1]; } - if(controlType.equals("javax.microedition.media.control.MIDIControl")) { return controls[2]; } - if(controlType.equals("javax.microedition.media.control.ToneControl")) { return controls[3]; } + if(controlType.contains("VolumeControl")) { return controls[0]; } + if(controlType.contains("TempoControl")) { return controls[1]; } + if(controlType.contains("MIDIControl")) { return controls[2]; } + if(controlType.contains("ToneControl")) { return controls[3]; } return null; } @@ -831,7 +850,7 @@ public boolean isRunning() // Controls // /* midiControl is untested */ - private class midiControl implements javax.microedition.media.control.MIDIControl + public class midiControl implements javax.microedition.media.control.MIDIControl { private midiPlayer player; @@ -1070,7 +1089,7 @@ public void shortMidiEvent(int type, int data1, int data2) } } - private class volumeControl implements javax.microedition.media.control.VolumeControl + public class volumeControl implements javax.microedition.media.control.VolumeControl { private int level = 100; private boolean muted = false; @@ -1166,7 +1185,7 @@ public void setMute(boolean mute) } /* This one hasn't been tested yet, no jar was found at the time it was implemented */ - private class tempoControl implements javax.microedition.media.control.TempoControl + public class tempoControl implements javax.microedition.media.control.TempoControl { /* MAX_RATE and MIN_RATE follow the JSR-135 docs guaranteed values, no matter if our player has a wider range */ private final int MAX_RATE = 300000; @@ -1243,7 +1262,7 @@ public int setRate(int millirate) } /* ToneControl is also almost entirely untested right now, couldn't find a jar that uses setSequence() */ - private class toneControl implements javax.microedition.media.control.ToneControl + public class toneControl implements javax.microedition.media.control.ToneControl { private midiPlayer player;