diff --git a/src/com/sprintpcs/media/Clip.java b/src/com/sprintpcs/media/Clip.java index 5206be27..3aeb5f51 100644 --- a/src/com/sprintpcs/media/Clip.java +++ b/src/com/sprintpcs/media/Clip.java @@ -35,8 +35,6 @@ public class Clip public Clip(String locator, String contentType, int priority, int vibration) throws IOException { - Mobile.log(Mobile.LOG_WARNING, Clip.class.getPackage().getName() + "." + Clip.class.getSimpleName() + ": " + "Clip (String, String, int, int)"); - this.locator = locator; this.contentType = contentType; this.priority = priority; @@ -45,8 +43,6 @@ public Clip(String locator, String contentType, int priority, int vibration) thr public Clip(byte[] stream, String contentType, int priority, int vibration) throws IOException { - Mobile.log(Mobile.LOG_WARNING, Clip.class.getPackage().getName() + "." + Clip.class.getSimpleName() + ": " + "Clip (byte[], String, int, int)"); - this.stream = stream; this.contentType = contentType; this.priority = priority; @@ -59,14 +55,21 @@ public Clip(byte[] stream, String contentType, int priority, int vibration) thro protected Player getPlayer() throws MediaException { - Mobile.log(Mobile.LOG_WARNING, Clip.class.getPackage().getName() + "." + Clip.class.getSimpleName() + ": " + "GetPlayer()"); - Player player = null; try { if (stream != null) { player = Manager.createPlayer(new ByteArrayInputStream(stream), contentType); } - else { player = Manager.createPlayer(locator); } - } + else + { + // JAMDAT's Solitaire Deluxe prepends "resource:" before the actual resource location, also is the only sprint jar i've seen do this (and load data with locators) + if(locator.contains(":")) + { + int lastIndex = locator.lastIndexOf(":"); + + return Manager.createPlayer(Mobile.getResourceAsStream(null, locator.substring(lastIndex + 1)), contentType); + } + } + } catch (IOException e) { Mobile.log(Mobile.LOG_WARNING, Clip.class.getPackage().getName() + "." + Clip.class.getSimpleName() + ": " + "failed to getPlayer: " + e.getMessage()); } return player; diff --git a/src/com/sprintpcs/media/DualTone.java b/src/com/sprintpcs/media/DualTone.java index 546ae98d..fdbb47fd 100644 --- a/src/com/sprintpcs/media/DualTone.java +++ b/src/com/sprintpcs/media/DualTone.java @@ -35,18 +35,18 @@ public class DualTone private static final int PPQ = 24; // Ticks per quarter note private static final int BPM = 120; // Default BPM, not sure if DTFM changes this private static final double TICKS_PER_MILLISECOND = PPQ / (BPM * 4.0); // 4 quarter notes in a minute - byte[] sequence; - int loops; - - /* x-frequencies (high freqs?), y-frequencies (low freqs?), note duration, unknown, loops? */ + int priority, vibration; /* Implementation Idea: Dual Tone can just be made a single midi sequence with two tracks, one for each tone sequence. */ - public DualTone(int[] x_frequencies, int[] y_frequencies, int[] durations, int unknown, int loops) + public DualTone(int[] x_frequencies, int[] y_frequencies, int[] durations, int priority, int vibration) { try { + this.priority = priority; + this.vibration = vibration; + Sequence midiSequence = new Sequence(Sequence.PPQ, PPQ); Track trackA = midiSequence.createTrack(); Track trackB = midiSequence.createTrack(); @@ -85,6 +85,10 @@ public DualTone(int[] x_frequencies, int[] y_frequencies, int[] durations, int u } } + public int getPriority() { return priority; } + + public int getVibration() { return vibration; } + private int convertFreqToNote(int frequency) { return (int) (Math.round(Math.log((double) frequency / 8.176) * SEMITONE_CONST)); // Adjust to MIDI note A4 (440 Hz = note 69) diff --git a/src/com/sprintpcs/media/Player.java b/src/com/sprintpcs/media/Player.java index 87a6dbcf..a9cec150 100644 --- a/src/com/sprintpcs/media/Player.java +++ b/src/com/sprintpcs/media/Player.java @@ -27,24 +27,25 @@ public class Player { private static javax.microedition.media.Player player; + private static PlayerListener listener; private static int priority; public static void play(Clip clip, int repeat) { - Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "Untested"); - if (repeat < -1) { throw new IllegalArgumentException("Invalid repeat value was received"); } if (clip.getPriority() < priority) { - Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "Clip priority check."); + Mobile.log(Mobile.LOG_INFO, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "new Clip priority lower than current media."); return; } + priority = clip.getPriority(); + if (player != null) { player.close(); } try { player = clip.getPlayer(); } - catch (Exception e) { Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to play media: " + e.getMessage()); } + catch (Exception e) { Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to prepare Clip media: " + e.getMessage()); } if (repeat != -1 /* Clip.LOOP_CONTINUOUSLY */) { player.setLoopCount(repeat+1); } @@ -52,34 +53,59 @@ public static void play(Clip clip, int repeat) Mobile.vibrationDuration = clip.getVibration(); - try { player.start(); } - catch (Exception e) { e.printStackTrace(); } + try + { + player.start(); + listener.playerUpdate(PlayerListener.STARTED, player.getMediaTime()); + } + catch (Exception e) { Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to play Clip media: " + e.getMessage()); } } public static void play(DualTone dTone, int repeat) // I assume the second argument is repeat, there's no documentation for it { if (repeat < -1) { throw new IllegalArgumentException("Invalid repeat value was received"); } + if (dTone.getPriority() < priority) + { + Mobile.log(Mobile.LOG_INFO, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "new DualTone priority lower than current media."); + return; + } + + priority = dTone.getPriority(); + if (player != null) { player.close(); } try { player = Manager.createPlayer(new ByteArrayInputStream(dTone.sequence), "audio/mid"); } - catch (Exception e) { Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to prepare tone media: " + e.getMessage()); } + catch (Exception e) { Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to prepare DualTone media: " + e.getMessage()); } - if (repeat != -1 /* Clip.LOOP_CONTINUOUSLY */) { player.setLoopCount(repeat+1); } else { player.setLoopCount(repeat); } + + Mobile.vibrationDuration = dTone.getVibration(); - try { player.start(); } + try + { + player.start(); + listener.playerUpdate(PlayerListener.STARTED, player.getMediaTime()); + } catch (Exception e) { - Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to play media: " + e.getMessage()); + Mobile.log(Mobile.LOG_WARNING, Player.class.getPackage().getName() + "." + Player.class.getSimpleName() + ": " + "failed to play DualTone media: " + e.getMessage()); } } - public static void stop() { - if (player != null) { - player.close(); - player = null; - } + public static void resume() { player.start(); } + + public static void addPlayerListener(PlayerListener playerListener) { listener = playerListener; } + + public static void removePlayerListener(PlayerListener playerListener) { listener = null; } + + public static void stop() + { + if (player != null) + { + player.stop(); + listener.playerUpdate(PlayerListener.STOPPED, player.getMediaTime()); + } } } \ No newline at end of file diff --git a/src/com/sprintpcs/media/PlayerListener.java b/src/com/sprintpcs/media/PlayerListener.java new file mode 100644 index 00000000..1938f9ff --- /dev/null +++ b/src/com/sprintpcs/media/PlayerListener.java @@ -0,0 +1,31 @@ +/* + This file is part of FreeJ2ME. + + FreeJ2ME is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FreeJ2ME 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeJ2ME. If not, see http://www.gnu.org/licenses/ +*/ +package com.sprintpcs.media; + +public interface PlayerListener extends javax.microedition.media.PlayerListener +{ + public static final int AUDIO_DEVICE_UNAVAILABLE = 0; + public static final int END_OF_DATA = 1; + public static final int ERROR = 2; + public static final int STARTED = 3; + public static final int STOPPED = 4; + public static final int PAUSED = 5; + public static final int RESUME = 6; + public static final int PREEMPTED = 7; + + public void playerUpdate(int event, Object eventData); +} \ No newline at end of file