0001: /*
0002: * Copyright (c) 2007, Sun Microsystems, Inc.
0003: *
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * * Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: * * Redistributions in binary form must reproduce the above copyright
0013: * notice, this list of conditions and the following disclaimer in
0014: * the documentation and/or other materials provided with the
0015: * distribution.
0016: * * Neither the name of Sun Microsystems, Inc. nor the names of its
0017: * contributors may be used to endorse or promote products derived
0018: * from this software without specific prior written permission.
0019: *
0020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
0023: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
0024: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0031: */
0032:
0033: package example.mmademo;
0034:
0035: import java.util.*;
0036: import java.io.*;
0037: import javax.microedition.midlet.*;
0038: import javax.microedition.lcdui.*;
0039: import javax.microedition.media.*;
0040: import javax.microedition.media.control.*;
0041:
0042: /**
0043: * GUI functionality for SimplePlayer.
0044: * This class is used by SimplePlayerCanvas and SimplePlayerForm and
0045: * provides the actual logic.
0046: * SimplePlayerCanvas and SimplePlayerForm provide the interaction of
0047: * the main window with the user.
0048: *
0049: * @version 1.10
0050: */
0051: public class SimplePlayerGUI implements CommandListener,
0052: PlayerListener, ItemStateListener {
0053: // IMPL NOTE: used for the form-based player for video
0054: // if you set this to false, the currently active player is used
0055: private final static boolean USE_FORM_PLAYER_FOR_VIDEO = false;
0056:
0057: // maximum rate to support, in percent
0058: private final static int LIMIT_RATE = 300;
0059:
0060: // loop
0061: private static final int LOOP_ONCE = 0;
0062: private static final int LOOP_3 = 1;
0063: private static final int LOOP_INF = 2;
0064: private int loopmode = LOOP_ONCE;
0065:
0066: // timer (for time display and karaoke asynchronous event)
0067: private static final int DEFAULT_TIMER_INTERVAL = 50;
0068: private int timerInterval = DEFAULT_TIMER_INTERVAL;
0069:
0070: // gauge
0071: private static final int GAUGE_NONE = -1;
0072: private static final int GAUGE_VOLUME = 0; // gauge is used as volume slider
0073: private static final int GAUGE_RATE = 1; // gauge is used as rate slider
0074: private static final int GAUGE_TEMPO = 2; // gauge is used as tempo slider
0075: private static final int GAUGE_PITCH = 3; // gauge is used as pitch slider
0076: private int gaugeMode = GAUGE_NONE;
0077: private Gauge gauge = null;
0078: private StringItem gaugeLabel = null;
0079: private Form gaugeForm = null;
0080:
0081: // display timer
0082: private Timer guiTimer = null;
0083: private TimerTask timeDisplayTask = null;
0084:
0085: // Commands
0086: Command backCommand = new Command("Back", Command.BACK, 1); // is used in SimplePlayerCanvas
0087: private Command playCommand = new Command("Play", Command.ITEM, 1);
0088: private Command stopCommand = new Command("Stop", Command.ITEM, 1);
0089: private Command metaCommand = new Command("META data",
0090: Command.ITEM, 3);
0091: private Command volCommand = new Command("Volume", Command.ITEM, 2);
0092: private Command muteCommand = new Command("Mute", Command.ITEM, 1);
0093: private Command unmuteCommand = new Command("Unmute", Command.ITEM,
0094: 1);
0095: private Command loopCommand = new Command("Loopmode", Command.ITEM,
0096: 4);
0097: private Command stcCommand = new Command("Stop in 5 sec",
0098: Command.ITEM, 4);
0099: private Command selectCommand = new Command("Select", Command.ITEM,
0100: 1);
0101: private Command skipFwCommand = new Command("Skip Forward",
0102: Command.ITEM, 5);
0103: private Command skipBwCommand = new Command("Skip Backward",
0104: Command.ITEM, 5);
0105: private Command rewindCommand = new Command("Rewind", Command.ITEM,
0106: 5);
0107: private Command rateCommand = new Command("Rate", Command.ITEM, 5);
0108: private Command tempoCommand = new Command("Tempo", Command.ITEM, 5);
0109: private Command pitchCommand = new Command("Pitch", Command.ITEM, 5);
0110: private Command fullScreenCommand = new Command("Full Screen: ON",
0111: Command.ITEM, 5);
0112: private Command normalScreenCommand = new Command(
0113: "Full Screen: OFF", Command.ITEM, 5);
0114: private Command startRecordCommand = new Command("Start Recording",
0115: Command.ITEM, 5);
0116: private Command stopRecordCommand = new Command("Stop Recording",
0117: Command.ITEM, 5);
0118: private Command helpCommand = new Command("Quick Help",
0119: Command.ITEM, 10);
0120:
0121: // display
0122: private Parent parent;
0123: private Displayable display;
0124: private static Image logo = null;
0125:
0126: // full screen
0127: private boolean fullScreen = false;
0128:
0129: // recording
0130: private boolean isRecording = false;
0131: private String recordLocator = "file:///root1/recording.wav";
0132:
0133: // the player instance
0134: private Player player = null;
0135:
0136: // song descriptors
0137: private String title;
0138: private InputStream songInputStream;
0139: private String durationStr;
0140: private String songContentType = "";
0141: private String songLocator = "";
0142: private String songName = "";
0143: private String[] songDisplayNames = new String[0];
0144: private int currSongDisplay = 0;
0145: private int changeSongDisplayCounter = 0;
0146: private static final int SONG_DISPLAY_COUNTER = 2000 / DEFAULT_TIMER_INTERVAL; // 2 seconds
0147:
0148: // karaoke support
0149: private final static int LYRICS_EVENT = 0x60; // not an official event
0150: private final static String LYRICS_KEY = "lyrics"; // not an official key for MetaDataControl
0151: // indexes in params array returned by getKaraokeStr()
0152: public final static int KARAOKE_LINE_COUNT = 0;
0153: public final static int KARAOKE_LINE = 1;
0154: public final static int KARAOKE_LINE_INDEX = 2;
0155: public final static int KARAOKE_SYLLABLE_LENGTH = 3;
0156:
0157: private boolean karaokeMode = false;
0158: private String karaokeLyrics = "";
0159: private int currKaraokeLine = 0;
0160: private int currKaraokeLinePos = 0;
0161: private int currKaraokeLength = 0;
0162: private String[] karaokeLines = null;
0163: private int[] karaokeLinePos = null; // start position in karaokeLyrics for each line
0164: private int karaokeLineCount = 0;
0165: private int redisplayKaraokeCounter = 0; // asynchronous switch to next Karaoke page
0166: private int nextKaraokePos = 0; // for asynchronous display of next line/phrase
0167:
0168: // pause/resume support
0169: private boolean restartOnResume = false;
0170:
0171: private static void debugOut(String s) {
0172: Utils.debugOut("SimplePlayerGUI: " + s);
0173: }
0174:
0175: // /////////////////////////// INITIALIZATION /////////////////////////////
0176:
0177: /** Note: parent MUST be Displayable */
0178: public SimplePlayerGUI() {
0179: // initialize(String title, Parent parent) must be called after this
0180: }
0181:
0182: public void initialize(String title, Parent parent) {
0183: this .title = title;
0184: setParent(parent);
0185: initialize();
0186: }
0187:
0188: public void setParent(Parent parent) {
0189: this .parent = parent;
0190: if (!(parent instanceof Displayable)) {
0191: throw new RuntimeException(
0192: "parent must be instanceof Displayable!");
0193: }
0194: display = (Displayable) parent;
0195: display.addCommand(backCommand);
0196: display.setCommandListener(this );
0197: updateTime();
0198: updateRate(null);
0199: updateTempo(null);
0200: durationUpdated();
0201: parent.updateKaraoke();
0202: parent.updateDisplay();
0203: }
0204:
0205: private void initialize() {
0206: karaokeMode = false;
0207: karaokeLyrics = "";
0208: currKaraokeLine = 0;
0209: currKaraokeLinePos = 0;
0210: currKaraokeLength = 0;
0211: karaokeLines = null;
0212: karaokeLinePos = null;
0213: karaokeLineCount = 0;
0214: redisplayKaraokeCounter = 0;
0215: removeCommands();
0216: setStatus("");
0217: durationStr = "";
0218: setSong("No song loaded", "");
0219: guiTimer = new Timer();
0220: }
0221:
0222: public void setSong(String name, String locator) {
0223: songLocator = locator;
0224: songInputStream = null;
0225: songContentType = "";
0226: doSetSong(name);
0227: }
0228:
0229: public void setSong(String name, InputStream is, String contentType) {
0230: songLocator = "";
0231: songInputStream = is;
0232: songContentType = contentType;
0233: doSetSong(name);
0234: }
0235:
0236: public void setSong(String name, Player player) {
0237: songLocator = "";
0238: songInputStream = null;
0239: songContentType = "";
0240: doSetSong(name);
0241: this .player = player;
0242: }
0243:
0244: private void doSetSong(String name) {
0245: songName = name;
0246: songDisplayNames = new String[1];
0247: songDisplayNames[0] = name;
0248: currSongDisplay = 0;
0249: closePlayer();
0250: setStatus("");
0251: setFeedback("");
0252: clearKaraoke();
0253: updateTempo(null);
0254: updateTime();
0255: updateSongDisplay();
0256: }
0257:
0258: public void setTimerInterval(int millis) {
0259: timerInterval = millis;
0260: }
0261:
0262: // /////////////////////////// VISUAL FEEDBACK ////////////////////////////
0263:
0264: private void error(Throwable e) {
0265: error(Utils.friendlyException(e));
0266: if (Utils.DEBUG)
0267: e.printStackTrace();
0268: }
0269:
0270: private void error(String s) {
0271: setFeedback(s);
0272: }
0273:
0274: private void setStatus(String s) {
0275: parent.setStatus(s);
0276: if (Utils.DEBUG)
0277: System.out.println("Status: " + s);
0278: }
0279:
0280: private void setFeedback(String s) {
0281: parent.setFeedback(s);
0282: if (Utils.DEBUG)
0283: System.out.println("Feedback: " + s);
0284: }
0285:
0286: private void updateKaraoke() {
0287: parent.updateKaraoke();
0288: }
0289:
0290: private void updateTime() {
0291: parent.updateTime();
0292: }
0293:
0294: private void updateRate(RateControl c) {
0295: parent.updateRate();
0296: // if the rate gauge is activated, update it
0297: if (gauge != null && gaugeMode == GAUGE_RATE) {
0298: if (c == null) {
0299: c = getRateControl();
0300: }
0301: if (c != null) {
0302: String disp = getRateStr();
0303: // or
0304: // gauge.setValue((c.getRate() - c.getMinRate() + 1)/1000);
0305: gauge.setValue((c.getRate() - c.getMinRate()) / 1000);
0306: gaugeLabel.setLabel(disp);
0307: }
0308: }
0309: }
0310:
0311: private void updateTempo(TempoControl c) {
0312: parent.updateRate();
0313: // if the tempo gauge is activated, update it
0314: if (gauge != null && gaugeMode == GAUGE_TEMPO) {
0315: if (c == null) {
0316: c = getTempoControl();
0317: }
0318: if (c != null) {
0319: String disp = getTempoStr();
0320: gauge.setValue((c.getTempo() / 1000) - 1);
0321: gaugeLabel.setLabel(disp);
0322: }
0323: }
0324: }
0325:
0326: private void updateVolume(VolumeControl c) {
0327: if (c == null) {
0328: c = getVolumeControl();
0329: }
0330: if (c != null) {
0331: int l = c.getLevel();
0332: String disp = "Volume: " + String.valueOf(l);
0333: if (c.isMuted()) {
0334: disp += " (muted)";
0335: }
0336: if (gauge != null && gaugeMode == GAUGE_VOLUME) {
0337: gauge.setValue(l);
0338: gaugeLabel.setLabel(disp);
0339: }
0340: setFeedback(disp);
0341: }
0342: }
0343:
0344: private void updatePitch(PitchControl c) {
0345: if (c == null) {
0346: c = getPitchControl();
0347: }
0348: if (c != null) {
0349: String disp = "Transpose: "
0350: + toFloatString(c.getPitch(), 3) + " semi tones";
0351: // if the pitch gauge is activated, update it
0352: if (gauge != null && gaugeMode == GAUGE_PITCH) {
0353: // WTK removed the next line
0354: gauge.setValue((c.getPitch() - c.getMinPitch()) / 1000);
0355: gaugeLabel.setLabel(disp);
0356: }
0357: setFeedback(disp);
0358: }
0359: }
0360:
0361: private void updateLoop() {
0362: if (player != null) {
0363: try {
0364: int loop = 1;
0365: switch (loopmode) {
0366: case LOOP_ONCE:
0367: loop = 1;
0368: break;
0369: case LOOP_3:
0370: loop = 3;
0371: break;
0372: case LOOP_INF:
0373: loop = -1;
0374: break;
0375: }
0376: boolean restart = false;
0377: if (player.getState() == player.STARTED) {
0378: player.stop();
0379: restart = true;
0380: }
0381: player.setLoopCount(loop);
0382: if (restart) {
0383: player.start();
0384: }
0385:
0386: } catch (Exception e) {
0387: error(e);
0388: }
0389: }
0390: }
0391:
0392: private void updateSongDisplay() {
0393: String add = "";
0394: if (currSongDisplay == 0) {
0395: add = durationStr;
0396: }
0397: parent.setFileTitle(songDisplayNames[currSongDisplay] + add);
0398: }
0399:
0400: private void durationUpdated() {
0401: if (player != null) {
0402: // include duration in song name
0403: try {
0404: long duration = player.getDuration();
0405: if (duration >= 0) {
0406: durationStr = " (" + timeDisplay(duration) + ")";
0407: } else {
0408: durationStr = "";
0409: }
0410: } catch (IllegalStateException ise) {
0411: // thrown in CLOSED state
0412: durationStr = "";
0413: }
0414: updateSongDisplay();
0415: }
0416: }
0417:
0418: private void clearKaraoke() {
0419: karaokeLineCount = 0;
0420: nextKaraokePos = -1;
0421: redisplayKaraokeCounter = 0;
0422: updateKaraoke();
0423: }
0424:
0425: // /////////////////////////// DISPLAY UTILITIES //////////////////////////
0426:
0427: public Image getLogo() {
0428: if (logo == null) {
0429: try {
0430: logo = Image.createImage("/icons/logo.png");
0431: } catch (Exception ex) {
0432: logo = null;
0433: }
0434: if (logo == null) {
0435: debugOut("can not load logo.png");
0436: }
0437: }
0438: return logo;
0439: }
0440:
0441: private String toFloatString(int number, int digitsAfterDot) {
0442: StringBuffer ret = new StringBuffer(String.valueOf(number));
0443: while (ret.length() < (digitsAfterDot + 1)) {
0444: ret.insert(0, '0');
0445: }
0446: ret.insert(ret.length() - digitsAfterDot, '.');
0447: return ret.toString();
0448: }
0449:
0450: private String formatNumber(long num, int len, boolean leadingZeros) {
0451: StringBuffer ret = new StringBuffer(String.valueOf(num));
0452: if (leadingZeros) {
0453: while (ret.length() < len) {
0454: ret.insert(0, '0');
0455: }
0456: } else {
0457: while (ret.length() < len) {
0458: ret.append('0');
0459: }
0460: }
0461: return ret.toString();
0462: }
0463:
0464: private String timeDisplay(long us) {
0465: long ts = us / 100000;
0466: return formatNumber(ts / 600l, 2, true) + ":"
0467: + formatNumber(((ts % 600) / 10), 2, true) + "."
0468: + String.valueOf(ts % 10);
0469: }
0470:
0471: public String getMediaTimeStr() {
0472: try {
0473: if (player != null) {
0474: return timeDisplay(player.getMediaTime());
0475: }
0476: } catch (IllegalStateException ise) {
0477: // thrown when player is closed
0478: }
0479: return "--:--:-";
0480: }
0481:
0482: public String getTempoStr() {
0483: if (player != null) {
0484: TempoControl tc = getTempoControl();
0485: if (tc != null) {
0486: int tempo = tc.getTempo();
0487: return toFloatString((tempo + 50) / 100, 1)
0488: + "bpm (eff: "
0489: + toFloatString(
0490: (int) (((((long) tc.getRate())
0491: * ((long) tempo) / 100000) + 50) / 100l),
0492: 1) + ")";
0493: }
0494: }
0495: return "";
0496: }
0497:
0498: public String getRateStr() {
0499: if (player != null) {
0500: RateControl rc = getRateControl();
0501: if (rc != null) {
0502: return "Rate: " + toFloatString(rc.getRate() / 100, 1)
0503: + "%";
0504: }
0505: }
0506: return "";
0507: }
0508:
0509: /**
0510: * switch to next karaoke screen
0511: */
0512: private void displayNextKaraokePhrase() {
0513: if (karaokeLyrics != null && karaokeLineCount > 0
0514: && karaokeLines != null && nextKaraokePos >= 0) {
0515: if (nextKaraokePos < karaokeLyrics.length()
0516: && nextKaraokePos > karaokeLinePos[currKaraokeLine]) {
0517: setupKaraokeLines(nextKaraokePos, 0);
0518: updateKaraoke();
0519: }
0520: }
0521: }
0522:
0523: private void addKaraokeLine(int start, int end) {
0524: if (karaokeLines == null
0525: || karaokeLines.length <= karaokeLineCount) {
0526: String[] newKL = new String[karaokeLineCount + 4];
0527: if (karaokeLines != null) {
0528: System.arraycopy(karaokeLines, 0, newKL, 0,
0529: karaokeLineCount);
0530: }
0531: karaokeLines = newKL;
0532: int[] newKLP = new int[karaokeLineCount + 5]; // one more than karaokeLines.length
0533: if (karaokeLinePos != null) {
0534: System.arraycopy(karaokeLinePos, 0, newKLP, 0,
0535: karaokeLineCount + 1);
0536: }
0537: karaokeLinePos = newKLP;
0538: }
0539: karaokeLines[karaokeLineCount] = karaokeLyrics.substring(start,
0540: end);
0541: karaokeLinePos[karaokeLineCount++] = start;
0542: }
0543:
0544: private void setupKaraokeLines(int pos, int syllableLen) {
0545: int len = (karaokeLyrics == null) ? 0 : karaokeLyrics.length();
0546: if (len == 0) {
0547: debugOut("no karaoke lyrics");
0548: return;
0549: }
0550: // cancel automatic display of next line if it is already displayed
0551: nextKaraokePos = -1;
0552: if (pos < 0 || pos >= len) {
0553: karaokeLineCount = 0;
0554: debugOut("setupKaraokeLines: pos out of bounds!");
0555: return;
0556: }
0557: // the strings in karaokeLines never start with a control character
0558: while (karaokeLyrics.charAt(pos) == '\\'
0559: || karaokeLyrics.charAt(pos) == '/') {
0560: pos++;
0561: syllableLen--;
0562: }
0563: if (syllableLen < 0) {
0564: syllableLen = 0;
0565: }
0566: if (karaokeLinePos == null || karaokeLineCount == 0
0567: || pos < karaokeLinePos[0]
0568: || pos >= karaokeLinePos[karaokeLineCount]) {
0569: // need to re-setup karaoke lines
0570: // first find the start of this phrase
0571: int startPos = pos;
0572: while (karaokeLyrics.charAt(startPos) != '\\'
0573: && startPos > 0) {
0574: startPos--;
0575: }
0576: if (karaokeLyrics.charAt(startPos) == '\\') {
0577: startPos++;
0578: }
0579: // now go through the lines and add them to karaokeLines array
0580: karaokeLineCount = 0;
0581: int endPos = startPos;
0582: while (endPos < len) {
0583: char c = karaokeLyrics.charAt(endPos);
0584: if (c == '/') {
0585: // new line
0586: addKaraokeLine(startPos, endPos);
0587: startPos = endPos + 1;
0588: } else if (c == '\\') {
0589: // end of phrase
0590: break;
0591: }
0592: endPos++;
0593: }
0594: addKaraokeLine(startPos, endPos);
0595: if (endPos < len) {
0596: endPos--;
0597: }
0598: karaokeLinePos[karaokeLineCount] = endPos;
0599: }
0600: // search the current line and position in the current line
0601: currKaraokeLength = 0;
0602: for (int i = 0; i < karaokeLineCount; i++) {
0603: if (pos >= karaokeLinePos[i] && pos < karaokeLinePos[i + 1]) {
0604: currKaraokeLine = i;
0605: currKaraokeLinePos = pos - karaokeLinePos[i];
0606: currKaraokeLength = syllableLen;
0607: //debugOut("For pos="+pos+" and syllLen="+syllableLen+", found line "+i+" . Set currKaraokeLinePos="+currKaraokeLinePos);
0608: if ((currKaraokeLinePos + syllableLen >= karaokeLines[i]
0609: .length())) {
0610: nextKaraokePos = karaokeLinePos[i + 1] + 1;
0611: redisplayKaraokeCounter = 100 / DEFAULT_TIMER_INTERVAL + 1; // approx. 100ms
0612: }
0613: break;
0614: }
0615: }
0616: }
0617:
0618: /**
0619: * OUT: params:
0620: * 0: number of valid strings in return array
0621: * 1: index in return array of currently sung line
0622: * 2: index in current line which is currently sung. if -1: nothing currently sung
0623: * 3: length of syllable currently sung.
0624: */
0625: public String[] getKaraokeStr(int[] params) {
0626: params[0] = karaokeLineCount;
0627: params[1] = currKaraokeLine;
0628: params[2] = currKaraokeLinePos;
0629: params[3] = currKaraokeLength;
0630: return karaokeLines;
0631: }
0632:
0633: // /////////////////////////// USER FLOW //////////////////////////////////
0634:
0635: private void goBack() {
0636: if (parent.getCurrentDisplayable() == display) {
0637: closePlayer();
0638: }
0639: Displayable now = parent.goBack();
0640: if (now == display) {
0641: // if main player window is showing
0642: setPlayerCommands();
0643: }
0644: }
0645:
0646: private void setPlayerCommands() {
0647: removeCommands();
0648: display.addCommand(backCommand);
0649: if (player != null) {
0650: if (getMetaDataControl() != null) {
0651: display.addCommand(metaCommand);
0652: }
0653: if (getStopTimeControl() != null) {
0654: display.addCommand(stcCommand);
0655: }
0656: VolumeControl vc = getVolumeControl();
0657: if (vc != null) {
0658: display.addCommand(volCommand);
0659: if (vc.isMuted()) {
0660: display.addCommand(unmuteCommand);
0661: } else {
0662: display.addCommand(muteCommand);
0663: }
0664: }
0665: if (getRateControl() != null) {
0666: display.addCommand(rateCommand);
0667: }
0668: if (getTempoControl() != null) {
0669: display.addCommand(tempoCommand);
0670: }
0671: if (getPitchControl() != null) {
0672: display.addCommand(pitchCommand);
0673: }
0674: if (getVideoControl() != null) {
0675: display.addCommand(normalScreenCommand);
0676: display.addCommand(fullScreenCommand);
0677: }
0678: if (getRecordControl() != null) {
0679: if (isRecording) {
0680: display.addCommand(stopRecordCommand);
0681: } else {
0682: display.addCommand(startRecordCommand);
0683: }
0684: }
0685: display.addCommand(loopCommand);
0686: if (player.getState() >= Player.STARTED) {
0687: display.addCommand(stopCommand);
0688: } else {
0689: display.addCommand(playCommand);
0690: }
0691: display.addCommand(skipFwCommand);
0692: display.addCommand(skipBwCommand);
0693: display.addCommand(rewindCommand);
0694: if (parent instanceof SimplePlayerCanvas) {
0695: // Canvas player uses the keys for control,
0696: // enable a simple help
0697: display.addCommand(helpCommand);
0698: }
0699: }
0700: }
0701:
0702: private void removeCommands() {
0703: display.removeCommand(muteCommand);
0704: display.removeCommand(unmuteCommand);
0705: display.removeCommand(metaCommand);
0706: display.removeCommand(volCommand);
0707: display.removeCommand(stcCommand);
0708: display.removeCommand(loopCommand);
0709: display.removeCommand(backCommand);
0710: display.removeCommand(playCommand);
0711: display.removeCommand(stopCommand);
0712: display.removeCommand(skipFwCommand);
0713: display.removeCommand(skipBwCommand);
0714: display.removeCommand(rewindCommand);
0715: display.removeCommand(rateCommand);
0716: display.removeCommand(tempoCommand);
0717: display.removeCommand(pitchCommand);
0718: display.removeCommand(fullScreenCommand);
0719: display.removeCommand(normalScreenCommand);
0720: display.removeCommand(startRecordCommand);
0721: display.removeCommand(stopRecordCommand);
0722: display.removeCommand(helpCommand);
0723: }
0724:
0725: // /////////////////////////// MENU ITEM HANDLERS /////////////////////////
0726:
0727: private void mutePressed() {
0728: VolumeControl c = getVolumeControl();
0729: if (c != null) {
0730: if (c.isMuted()) {
0731: //muteCommand.setLabel("Mute"); MIDP_NG only ?
0732: display.removeCommand(unmuteCommand);
0733: display.addCommand(muteCommand);
0734: c.setMute(false);
0735: } else {
0736: //muteCommand.setLabel("Unmute"); MIDP_NG only ?
0737: display.removeCommand(muteCommand);
0738: display.addCommand(unmuteCommand);
0739: c.setMute(true);
0740: }
0741: updateVolume(c);
0742: } else {
0743: setFeedback("No VolumeControl!");
0744: }
0745: }
0746:
0747: private void displayGauge(String title) {
0748: if (gaugeForm == null) {
0749: gaugeForm = new Form(title);
0750: gaugeForm.append(gauge);
0751: gaugeForm.append(gaugeLabel);
0752: gaugeForm.setItemStateListener(this );
0753: gaugeForm.addCommand(backCommand);
0754: gaugeForm.setCommandListener(this );
0755: }
0756: parent.go(gaugeForm);
0757: }
0758:
0759: private void volPressed() {
0760: VolumeControl c = getVolumeControl();
0761: if (c != null) {
0762: if (gauge == null || gaugeMode != GAUGE_VOLUME) {
0763: gauge = new Gauge("Volume", true, 100, c.getLevel());
0764: gaugeLabel = new StringItem("Volume", "");
0765: gaugeMode = GAUGE_VOLUME;
0766: gaugeForm = null;
0767: }
0768: displayGauge("Set Volume");
0769: updateVolume(c);
0770: } else {
0771: setFeedback("No VolumeControl!");
0772: }
0773: }
0774:
0775: private void ratePressed() {
0776: RateControl c = getRateControl();
0777: if (c != null) {
0778: if (gauge == null || gaugeMode != GAUGE_RATE) {
0779: int minRate = c.getMinRate() / 1000;
0780: int maxRate = c.getMaxRate() / 1000;
0781: // limit to LIMIT_RATE to improve usability
0782: if (maxRate > LIMIT_RATE) {
0783: maxRate = LIMIT_RATE;
0784: }
0785: int currRate = c.getRate() / 1000;
0786: gauge = new Gauge("Rate", true, maxRate - minRate,
0787: currRate - minRate);
0788: gaugeLabel = new StringItem("Rate", "");
0789: gaugeMode = GAUGE_RATE;
0790: gaugeForm = null;
0791: }
0792: displayGauge("Set Rate");
0793: updateRate(c);
0794: } else {
0795: setFeedback("No RateControl!");
0796: }
0797: }
0798:
0799: private void pitchPressed() {
0800: PitchControl c = getPitchControl();
0801: if (c != null) {
0802: if (gauge == null || gaugeMode != GAUGE_PITCH) {
0803: gauge = new Gauge("Pitch", true, (c.getMaxPitch() - c
0804: .getMinPitch()) / 1000, (c.getPitch() - c
0805: .getMinPitch()) / 1000);
0806: gaugeLabel = new StringItem("Pitch", "");
0807: gaugeMode = GAUGE_PITCH;
0808: gaugeForm = null;
0809: }
0810: displayGauge("Set Pitch");
0811: updatePitch(c);
0812: } else {
0813: setFeedback("No PitchControl!");
0814: }
0815: }
0816:
0817: private void tempoPressed() {
0818: TempoControl c = getTempoControl();
0819: if (c != null) {
0820: if (gauge == null || gaugeMode != GAUGE_TEMPO) {
0821: gauge = new Gauge("Tempo", true, 399,
0822: (c.getTempo() / 1000) - 1);
0823: gaugeLabel = new StringItem("Tempo", "");
0824: gaugeMode = GAUGE_TEMPO;
0825: gaugeForm = null;
0826: }
0827: displayGauge("Set Tempo");
0828: updateTempo(c);
0829: } else {
0830: setFeedback("No TempoControl!");
0831: }
0832: }
0833:
0834: private void metaPressed() {
0835: MetaDataControl c = getMetaDataControl();
0836: if (c != null) {
0837: List list = new List("Meta Data", Choice.IMPLICIT);
0838: String[] allkeys = c.getKeys();
0839: Utils.sort(allkeys);
0840: for (int i = 0; i < allkeys.length; i++) {
0841: try {
0842: if (!allkeys[i].equals(LYRICS_KEY)) {
0843: list.append(allkeys[i] + " = "
0844: + c.getKeyValue(allkeys[i]), null);
0845: }
0846: } catch (IllegalArgumentException t) {
0847: list.append(allkeys[i] + ": "
0848: + Utils.friendlyException(t), null);
0849: }
0850: }
0851: if (allkeys.length == 0) {
0852: list.append("No meta data", null);
0853: }
0854: list.addCommand(backCommand);
0855: list.setCommandListener(this );
0856: parent.go(list);
0857: } else {
0858: setFeedback("No MetaDataControl!");
0859: }
0860: }
0861:
0862: private void loopPressed() {
0863: loopmode = (loopmode + 1) % 3;
0864: String fb = "";
0865: switch (loopmode) {
0866: case LOOP_ONCE:
0867: fb = "one time";
0868: break;
0869: case LOOP_3:
0870: fb = "3 times";
0871: break;
0872: case LOOP_INF:
0873: fb = "infinite";
0874: break;
0875: }
0876: setFeedback("Set loop mode to " + fb);
0877: updateLoop();
0878: }
0879:
0880: public boolean isFullScreen() {
0881: // this may not be accurate - the user can modify that with the keys
0882: return fullScreen;
0883: }
0884:
0885: public boolean toggleFullScreen() {
0886: VideoControl vc = getVideoControl();
0887: Utils.debugOut("toggleFullScreen");
0888: if (vc != null) {
0889: try {
0890: vc.setDisplayFullScreen(!fullScreen);
0891: fullScreen = !fullScreen;
0892: parent.fullScreen(fullScreen);
0893: Utils
0894: .debugOut("Successfully set to "
0895: + (fullScreen ? "full screen"
0896: : "normal screen"));
0897: } catch (Exception e) {
0898: fullScreen = false;
0899: display.removeCommand(fullScreenCommand);
0900: display.removeCommand(normalScreenCommand);
0901: error(e);
0902: }
0903: } else {
0904: setFeedback("No VideoControl!");
0905: }
0906: return fullScreen;
0907: }
0908:
0909: private void fullScreenPressed() {
0910: fullScreen = false;
0911: toggleFullScreen();
0912: }
0913:
0914: private void normalScreenPressed() {
0915: fullScreen = true;
0916: toggleFullScreen();
0917: }
0918:
0919: public void stepFrame(int frames) {
0920: FramePositioningControl fpc = getFramePositioningControl();
0921: if (fpc != null) {
0922: fpc.skip(frames);
0923: } else {
0924: setFeedback("No FramePositioningControl!");
0925: }
0926: }
0927:
0928: // /////////////////////////// CONTROLS ///////////////////////////////////
0929:
0930: public boolean hasRateControl() {
0931: return getRateControl() != null;
0932: }
0933:
0934: public boolean hasTempoControl() {
0935: return getTempoControl() != null;
0936: }
0937:
0938: public boolean hasGUIControls() {
0939: // a player which provides VideoControl should also
0940: // always return GUIControl. Just to be sure...
0941: try {
0942: if (player != null) {
0943: return ((player.getControl("GUIControl") != null) || (player
0944: .getControl("VideoControl") != null));
0945: }
0946: } catch (IllegalStateException ise) {
0947: // thrown when player is closed
0948: }
0949: return false;
0950: }
0951:
0952: public Control[] getControls() {
0953: try {
0954: if (player != null) {
0955: return player.getControls();
0956: }
0957: } catch (IllegalStateException ise) {
0958: // thrown when player is closed
0959: }
0960: return null;
0961: }
0962:
0963: private VolumeControl getVolumeControl() {
0964: try {
0965: if (player != null) {
0966: return (VolumeControl) player
0967: .getControl("VolumeControl");
0968: }
0969: } catch (IllegalStateException ise) {
0970: // thrown when player is closed
0971: }
0972: return null;
0973: }
0974:
0975: private TempoControl getTempoControl() {
0976: try {
0977: if (player != null) {
0978: return (TempoControl) player.getControl("TempoControl");
0979: }
0980: } catch (IllegalStateException ise) {
0981: // thrown when player is closed
0982: }
0983: return null;
0984: }
0985:
0986: private RateControl getRateControl() {
0987: try {
0988: if (player != null) {
0989: return (RateControl) player.getControl("RateControl");
0990: }
0991: } catch (IllegalStateException ise) {
0992: // thrown when player is closed
0993: }
0994: return null;
0995: }
0996:
0997: private PitchControl getPitchControl() {
0998: try {
0999: if (player != null) {
1000: return (PitchControl) player.getControl("PitchControl");
1001: }
1002: } catch (IllegalStateException ise) {
1003: // thrown when player is closed
1004: }
1005: return null;
1006: }
1007:
1008: private MetaDataControl getMetaDataControl() {
1009: try {
1010: if (player != null) {
1011: return (MetaDataControl) player
1012: .getControl("MetaDataControl");
1013: }
1014: } catch (IllegalStateException ise) {
1015: // thrown when player is closed
1016: }
1017: return null;
1018: }
1019:
1020: private FramePositioningControl getFramePositioningControl() {
1021: try {
1022: if (player != null) {
1023: return (FramePositioningControl) player
1024: .getControl("FramePositioningControl");
1025: }
1026: } catch (IllegalStateException ise) {
1027: // thrown when player is closed
1028: }
1029: return null;
1030: }
1031:
1032: private StopTimeControl getStopTimeControl() {
1033: try {
1034: if (player != null) {
1035: return (StopTimeControl) player
1036: .getControl("StopTimeControl");
1037: }
1038: } catch (IllegalStateException ise) {
1039: // thrown when player is closed
1040: }
1041: return null;
1042: }
1043:
1044: public VideoControl getVideoControl() {
1045: try {
1046: if (player != null) {
1047: return (VideoControl) player.getControl("VideoControl");
1048: }
1049: } catch (IllegalStateException ise) {
1050: // thrown when player is closed
1051: }
1052: return null;
1053: }
1054:
1055: public RecordControl getRecordControl() {
1056: try {
1057: if (player != null) {
1058: return (RecordControl) player
1059: .getControl("RecordControl");
1060: }
1061: } catch (IllegalStateException ise) {
1062: // thrown when player is closed
1063: }
1064: return null;
1065: }
1066:
1067: // /////////////////////////// PLAYBACK CONTROL ///////////////////////////
1068:
1069: private void assertPlayer() throws Throwable {
1070: String state = "";
1071: try {
1072: debugOut("assertPlayer");
1073: fullScreen = false;
1074: // make sure we can go back, even if failed
1075: display.removeCommand(backCommand);
1076: display.addCommand(backCommand);
1077: if (player == null) {
1078: if (songInputStream == null) {
1079: state = "Opening " + songLocator;
1080: setStatus(state + "...");
1081: player = Manager.createPlayer(songLocator);
1082: } else {
1083: state = "Opening " + songName;
1084: setStatus(state + "...");
1085: player = Manager.createPlayer(songInputStream,
1086: songContentType);
1087: }
1088: }
1089: player.addPlayerListener(this );
1090: //System.out.println("player = " + player);
1091: state = "Realizing";
1092: setStatus(state + "...");
1093: player.realize();
1094: state = "Prefetching";
1095: setStatus(state + "...");
1096: player.prefetch();
1097: state = "Prefetched";
1098: setStatus(state);
1099: if (USE_FORM_PLAYER_FOR_VIDEO) {
1100: // MAGIC: if there are any GUI controls, switch to Form mode
1101: // this is not nice design...
1102: if (hasGUIControls()
1103: && !(parent instanceof SimplePlayerForm)) {
1104: System.gc();
1105: state = "Setting up GUI";
1106: setStatus(state + "...");
1107: Parent newParent = new SimplePlayerForm(parent
1108: .getTitle(), this , parent.getParent());
1109: debugOut("created");
1110: setParent(newParent);
1111: parent.replaceCurrent(display);
1112: state = "GUI is set up.";
1113: setStatus(state);
1114: debugOut("Changed to form-based player.");
1115: }
1116: }
1117: setPlayerCommands();
1118: // notify the display class
1119: parent.setupDisplay();
1120:
1121: // use TITLE meta data if existant for display
1122: MetaDataControl mc = getMetaDataControl();
1123: if (mc != null) {
1124: int titleCount = 0;
1125: String title = "";
1126: try {
1127: title = mc.getKeyValue(MetaDataControl.TITLE_KEY);
1128: if (title != null && title != "") {
1129: titleCount++;
1130: while (true) {
1131: String n = mc
1132: .getKeyValue(MetaDataControl.TITLE_KEY
1133: + (titleCount + 1));
1134: if (n == null || n == "") {
1135: break;
1136: }
1137: titleCount++;
1138: }
1139: }
1140: } catch (IllegalArgumentException me) {
1141: // title key doesn't exist
1142: }
1143: // now number of titles is known
1144: if (titleCount > 0) {
1145: songDisplayNames = new String[titleCount];
1146: songDisplayNames[0] = title;
1147: try {
1148: for (int i = 1; i < titleCount; i++) {
1149: songDisplayNames[i] = mc
1150: .getKeyValue(MetaDataControl.TITLE_KEY
1151: + (i + 1));
1152: }
1153: } catch (IllegalArgumentException me) {
1154: }
1155: currSongDisplay = 0;
1156: }
1157: try {
1158: String l = mc.getKeyValue(LYRICS_KEY);
1159: if (l != null && l != "") {
1160: karaokeMode = true;
1161: karaokeLyrics = l;
1162: }
1163: } catch (IllegalArgumentException me) {
1164: // lyrics key doesn't exist
1165: }
1166: }
1167: durationUpdated();
1168: } catch (Throwable t) {
1169: player = null;
1170: setStatus("");
1171: throw new MediaException(Utils.friendlyException(t)
1172: + " at " + state);
1173: }
1174: }
1175:
1176: public void startPlayer() {
1177: try {
1178: debugOut("startPlayer");
1179: if (player == null || player.getState() < Player.PREFETCHED) {
1180: assertPlayer();
1181: }
1182: if (player == null || player.getState() >= Player.STARTED) {
1183: return;
1184: }
1185: updateLoop();
1186: // auto-rewind
1187: try {
1188: long duration = player.getDuration();
1189: if (duration != Player.TIME_UNKNOWN
1190: && player.getMediaTime() >= duration) {
1191: player.setMediaTime(0);
1192: }
1193: } catch (MediaException e) {
1194: // nothing to do
1195: }
1196: if (player.getMediaTime() == 0) {
1197: setupKaraokeLines(0, 0);
1198: updateKaraoke();
1199: } else {
1200: clearKaraoke();
1201: }
1202: setStatus("Starting...");
1203: player.start();
1204: setStatus("Playing");
1205: setFeedback("");
1206: // tempo may have changed due to new position
1207: updateTempo(null);
1208: } catch (Throwable t) {
1209: error(t);
1210: }
1211: }
1212:
1213: public void closePlayer() {
1214: if (player != null) {
1215: setStatus("Stopping...");
1216: try {
1217: player.stop();
1218: } catch (Exception e) {
1219: }
1220: setStatus("Closing...");
1221: player.close();
1222: setStatus("Closed");
1223: player = null;
1224: initialize();
1225: }
1226: }
1227:
1228: public void pausePlayer() {
1229: if (player != null) {
1230: setStatus("Stopping...");
1231: try {
1232: player.stop();
1233: } catch (Exception e) {
1234: }
1235: setStatus("Stopped");
1236: setFeedback("");
1237: }
1238: }
1239:
1240: public void togglePlayer() {
1241: if (player != null) {
1242: if (player.getState() == Player.STARTED) {
1243: pausePlayer();
1244: } else {
1245: startPlayer();
1246: }
1247: }
1248: }
1249:
1250: /** fast forward or fast backward */
1251: public void skip(boolean backwards) {
1252: if (player != null) {
1253: try {
1254: long mTime = player.getMediaTime();
1255: // default 10 sec
1256: long jump = 10000000;
1257: long duration = player.getDuration();
1258: if (duration >= 0) {
1259: // skip 5%
1260: jump = duration / 20;
1261: if (jump < 2000000)
1262: jump = 2000000; // Skip at least 2 seconds
1263: }
1264: if (backwards) {
1265: // Jump backward
1266: setMediaTime(mTime - jump);
1267: } else {
1268: // Jump forward
1269: setMediaTime(mTime + jump);
1270: }
1271: } catch (IllegalStateException ise) {
1272: // thrown when player is closed
1273: error(ise);
1274: }
1275: }
1276: }
1277:
1278: public void stopAfterTime() {
1279: int delay = 5000000; // 5 seconds
1280: StopTimeControl stc = getStopTimeControl();
1281: if (stc != null) {
1282: try {
1283: stc.setStopTime(StopTimeControl.RESET);
1284: stc.setStopTime(player.getMediaTime() + delay);
1285: setFeedback("Stop in " + (delay / 1000000)
1286: + " seconds.");
1287: } catch (IllegalStateException ise) {
1288: error(ise);
1289: }
1290: } else {
1291: setFeedback("No StopTimeControl!");
1292: }
1293: }
1294:
1295: public void changeRate(boolean slowdown) {
1296: int diff = 10000; // 10%
1297: if (slowdown) {
1298: diff = -diff;
1299: }
1300: RateControl rc = getRateControl();
1301: if (rc != null) {
1302: int ocr = rc.getRate();
1303: int ncr = ocr + diff;
1304: int maxRate = rc.getMaxRate();
1305: if (maxRate > LIMIT_RATE * 1000) {
1306: maxRate = LIMIT_RATE * 1000;
1307: }
1308: if (ncr >= rc.getMinRate() && ncr <= maxRate) {
1309: int ecr = rc.setRate(ncr);
1310: setFeedback("New rate: " + toFloatString(ecr, 3) + "%");
1311: updateRate(rc);
1312: // rate changes effective tempo.
1313: updateTempo(null);
1314: }
1315: } else {
1316: setFeedback("No RateControl!");
1317: }
1318: }
1319:
1320: public void setMediaTime(long time) {
1321: if (player == null) {
1322: return;
1323: }
1324: try {
1325: setFeedback("Set MediaTime to " + timeDisplay(time));
1326: player.setMediaTime(time);
1327: updateTime();
1328: clearKaraoke();
1329: updateTempo(null);
1330: } catch (Exception e) {
1331: error(e);
1332: }
1333: }
1334:
1335: public void changeVolume(boolean decrease) {
1336: int diff = 10;
1337: if (decrease) {
1338: diff = -diff;
1339: }
1340: VolumeControl vc = getVolumeControl();
1341: if (vc != null) {
1342: int cv = vc.getLevel();
1343: cv += diff;
1344: vc.setLevel(cv);
1345: updateVolume(vc);
1346: } else {
1347: setFeedback("No VolumeControl!");
1348: }
1349: }
1350:
1351: public void toggleMute() {
1352: VolumeControl vc = getVolumeControl();
1353: if (vc != null) {
1354: vc.setMute(!vc.isMuted());
1355: updateVolume(vc);
1356: } else {
1357: setFeedback("No VolumeControl!");
1358: }
1359: }
1360:
1361: public void transpose(boolean down) {
1362: int diff = 1000; // 1 semitone
1363: if (down) {
1364: diff = -diff;
1365: }
1366: PitchControl pc = getPitchControl();
1367: if (pc != null) {
1368: pc.setPitch(pc.getPitch() + diff);
1369: updatePitch(pc);
1370: } else {
1371: // if no PitchControl, use FramePositioningControl
1372: if (getFramePositioningControl() != null) {
1373: skipFrame(down);
1374: } else {
1375: setFeedback("No PitchControl!");
1376: }
1377: }
1378: }
1379:
1380: public void skipFrame(boolean back) {
1381: int diff = 1; // 1 frame
1382: if (back) {
1383: diff = -diff;
1384: }
1385: FramePositioningControl fpc = getFramePositioningControl();
1386: if (fpc != null) {
1387: int res = fpc.skip(diff);
1388: updateTime();
1389: setFeedback("Skipped: " + res + " frames to "
1390: + fpc.mapTimeToFrame(player.getMediaTime()));
1391: } else {
1392: setFeedback("No FramePositioningControl!");
1393: }
1394: }
1395:
1396: private void queryRecording() {
1397: try {
1398: // display the screen to enter the locator
1399: Utils.query("Enter a record locator", recordLocator, 200,
1400: TextField.URL, new RecordTask(), parent);
1401: } catch (Exception e) {
1402: Utils.error(e, parent);
1403: }
1404: }
1405:
1406: private void startRecording(String locator) {
1407: try {
1408: if (locator == null || locator == "") {
1409: Utils.error("No locator set!", parent);
1410: } else {
1411: // user entered the locator.
1412: recordLocator = locator;
1413: //Start recording
1414: RecordControl rc = getRecordControl();
1415: if (rc != null) {
1416: rc.stopRecord();
1417: rc.reset();
1418: rc.setRecordLocation(locator);
1419: rc.startRecord();
1420: } else {
1421: throw new MediaException(
1422: "Could not get RecordControl!");
1423: }
1424: }
1425: } catch (Exception e) {
1426: Utils.error(e, parent);
1427: }
1428: }
1429:
1430: private void stopRecording() {
1431: try {
1432: // Stop recording
1433: final RecordControl rc = getRecordControl();
1434: if (rc != null) {
1435: rc.stopRecord();
1436: // The commit() must be performed in a thread that is not this one:
1437: // we are running on the event dispatcher thread.
1438: // rc.commit() MIGHT display a security dialog (depending on the URL
1439: // that the audio is being recorded to) and the MIDP spec recommends
1440: // performing actions that could bring up a security dialog
1441: // on a thread that is NOT the event dispatcher thread.
1442: new Thread(new Runnable() {
1443: public void run() {
1444: try {
1445: rc.commit();
1446: Utils.FYI("Recorded " + recordLocator
1447: + " successfully.", parent);
1448: } catch (Exception e) {
1449: Utils.error(e, parent);
1450: }
1451: }
1452: }).start();
1453: } else {
1454: throw new MediaException("Could not get RecordControl!");
1455: }
1456: } catch (Exception e) {
1457: Utils.error(e, parent);
1458: }
1459: }
1460:
1461: private void showHelp() {
1462: // only available for canvas player
1463: if (parent instanceof SimplePlayerCanvas) {
1464: ((SimplePlayerCanvas) parent).showHelp();
1465: }
1466: }
1467:
1468: // /////////////////////////// EVENT HANDLERS /////////////////////////////
1469:
1470: public void commandAction(Command c, Displayable s) {
1471: if (c == backCommand) {
1472: goBack();
1473: } else if (c == muteCommand || c == unmuteCommand) {
1474: mutePressed();
1475: } else if (c == volCommand) {
1476: volPressed();
1477: } else if (c == metaCommand) {
1478: metaPressed();
1479: } else if (c == loopCommand) {
1480: loopPressed();
1481: } else if (c == stcCommand) {
1482: stopAfterTime();
1483: } else if (c == playCommand || c == stopCommand) {
1484: togglePlayer();
1485: } else if (c == skipFwCommand) {
1486: skip(false);
1487: } else if (c == skipBwCommand) {
1488: skip(true);
1489: } else if (c == rewindCommand) {
1490: setMediaTime(0);
1491: } else if (c == rateCommand) {
1492: ratePressed();
1493: } else if (c == tempoCommand) {
1494: tempoPressed();
1495: } else if (c == pitchCommand) {
1496: pitchPressed();
1497: } else if (c == fullScreenCommand) {
1498: fullScreenPressed();
1499: } else if (c == normalScreenCommand) {
1500: normalScreenPressed();
1501: } else if (c == startRecordCommand) {
1502: queryRecording();
1503: } else if (c == stopRecordCommand) {
1504: stopRecording();
1505: } else if (c == helpCommand) {
1506: showHelp();
1507: } else if (s != display) {
1508: // e.g. when list item in MetaData display list is pressed
1509: goBack();
1510: }
1511: }
1512:
1513: private synchronized void startDisplayTimer() {
1514: if (timeDisplayTask == null) {
1515: timeDisplayTask = new SPTimerTask();
1516: guiTimer.scheduleAtFixedRate(timeDisplayTask, 0,
1517: timerInterval);
1518: }
1519: }
1520:
1521: private synchronized void stopDisplayTimer() {
1522: if (timeDisplayTask != null) {
1523: timeDisplayTask.cancel();
1524: timeDisplayTask = null;
1525: updateTime();
1526: }
1527: }
1528:
1529: public void playerUpdate(Player plyr, String evt, Object evtData) {
1530: try {
1531: // special case: end-of-media, but loop count>1 !
1532: if (evt == END_OF_MEDIA
1533: && plyr.getState() == Player.STARTED) {
1534: setFeedback("Looping");
1535: return;
1536: }
1537: if (evt == CLOSED || evt == ERROR || evt == END_OF_MEDIA
1538: || evt == STOPPED_AT_TIME || evt == STOPPED) {
1539: stopDisplayTimer();
1540: }
1541: if (evt == END_OF_MEDIA || evt == STOPPED_AT_TIME
1542: || evt == STOPPED || evt == ERROR) {
1543: display.removeCommand(stopCommand);
1544: display.addCommand(playCommand);
1545: changeSongDisplayCounter = 0;
1546: currSongDisplay = 0;
1547: updateSongDisplay();
1548: }
1549: // Sun-specific event for karaoke lyrics
1550: if (evt.equals("com.sun.midi.lyrics")) {
1551: // META data
1552: byte[] data = (byte[]) evtData;
1553: if (data != null && (evtData instanceof byte[])
1554: && data.length > 0) {
1555: if (Utils.DEBUG)
1556: System.out.println("META event 0x"
1557: + Integer.toHexString(data[0] & 0xFF));
1558: switch (data[0]) {
1559: case 0x01: // Text (commonly used for Karaoke, but not sent if Player is in Karaoke mode)
1560: // fall through
1561: case 0x05: // Lyrics (isn't this meant for Karaoke ??)
1562: if (karaokeMode) {
1563: break;
1564: }
1565: // fall through if not Karaoke
1566: case 0x06: // marker
1567: // fall through
1568: case 0x07: // Cue point
1569: String text = new String(data, 1,
1570: data.length - 1);
1571: setFeedback(text);
1572: if (Utils.DEBUG)
1573: System.out
1574: .println("META event 0x"
1575: + Integer
1576: .toHexString(data[0] & 0xFF)
1577: + ": " + text);
1578: break;
1579: case 0x51: // Tempo
1580: updateTempo(null);
1581: break;
1582: case LYRICS_EVENT: // inofficial lyrics event: data 1-3 pos, 4-6 length
1583: int kPos = (data[1] << 16) | (data[2] << 8)
1584: | (data[3] & 0xFF);
1585: int kLen = (data[4] << 16) | (data[5] << 8)
1586: | (data[6] & 0xFF);
1587: setupKaraokeLines(kPos, kLen);
1588: updateKaraoke();
1589: break;
1590: //case 0x58: // Time Signature
1591: //case 0x59: // Key Signature
1592: //case 0x7F: // Proprietary
1593: }
1594: }
1595: }
1596:
1597: if (evt == STARTED) {
1598: if (songDisplayNames.length > 1) {
1599: changeSongDisplayCounter = SONG_DISPLAY_COUNTER * 2;
1600: }
1601: startDisplayTimer();
1602: display.addCommand(stopCommand);
1603: display.removeCommand(playCommand);
1604: } else if (evt == DEVICE_UNAVAILABLE) {
1605: setFeedback("Audio device not available!");
1606: } else if (evt == BUFFERING_STARTED) {
1607: setFeedback("Buffering started");
1608: } else if (evt == BUFFERING_STOPPED) {
1609: setFeedback("Buffering stopped");
1610: } else if (evt == CLOSED) {
1611: setFeedback("Closed");
1612: } else if (evt == DURATION_UPDATED) {
1613: setFeedback("Duration updated");
1614: durationUpdated();
1615: } else if (evt == END_OF_MEDIA) {
1616: setStatus("End of media.");
1617: setFeedback("");
1618: } else if (evt == ERROR) {
1619: setFeedback("Error: " + ((String) evtData));
1620: } else if (evt == RECORD_STARTED) {
1621: isRecording = true;
1622: display.addCommand(stopRecordCommand);
1623: display.removeCommand(startRecordCommand);
1624: setFeedback("Recording Started");
1625: } else if (evt == RECORD_STOPPED) {
1626: isRecording = false;
1627: display.addCommand(startRecordCommand);
1628: display.removeCommand(stopRecordCommand);
1629: setFeedback("Recording Stopped");
1630: } else if (evt == SIZE_CHANGED) {
1631: VideoControl vc = (VideoControl) evtData;
1632: setFeedback("Resize to " + vc.getDisplayWidth() + "x"
1633: + vc.getDisplayHeight());
1634: } else if (evt == STOPPED_AT_TIME) {
1635: setStatus("Stopped at time.");
1636: setFeedback("");
1637: } else if (evt == VOLUME_CHANGED) {
1638: VolumeControl vc = (VolumeControl) evtData;
1639: setFeedback("New volume: " + vc.getLevel());
1640: updateVolume(vc);
1641: }
1642: } catch (Throwable t) {
1643: if (Utils.DEBUG)
1644: System.out
1645: .println("Uncaught Exception in SimplePlayerGUI.playerUpdate()");
1646: error(t);
1647: }
1648: }
1649:
1650: public void itemStateChanged(Item item) {
1651: if (item != null) {
1652: if (item == gauge) {
1653: switch (gaugeMode) {
1654: case GAUGE_VOLUME:
1655: VolumeControl vc = getVolumeControl();
1656: if (vc != null) {
1657: vc.setLevel(gauge.getValue());
1658: updateVolume(vc);
1659: }
1660: break;
1661: case GAUGE_RATE:
1662: RateControl rc = getRateControl();
1663: if (rc != null) {
1664: rc.setRate((gauge.getValue() * 1000)
1665: + rc.getMinRate());
1666: updateRate(rc);
1667: }
1668: break;
1669: case GAUGE_TEMPO:
1670: TempoControl tc = getTempoControl();
1671: if (tc != null) {
1672: tc.setTempo((gauge.getValue() + 1) * 1000);
1673: updateTempo(tc);
1674: }
1675: break;
1676: case GAUGE_PITCH:
1677: PitchControl pc = getPitchControl();
1678: if (pc != null) {
1679: pc.setPitch((gauge.getValue() * 1000)
1680: + pc.getMinPitch());
1681: updatePitch(pc);
1682: }
1683: break;
1684: } // switch
1685: }
1686: }
1687: }
1688:
1689: // ///////////////// PAUSE / RESUME ///////////////////////// //
1690:
1691: /**
1692: * Stop the player and the display thread.
1693: * Some VM's may stop players and threads
1694: * on their own, but for consistent user
1695: * experience, it's a good idea to explicitly
1696: * stop and start resources such as player
1697: * and threads.
1698: */
1699: public synchronized void pauseApp() {
1700: if (player != null && player.getState() >= Player.STARTED) {
1701: // player was playing, so stop it.
1702: try {
1703: player.stop();
1704: } catch (MediaException e) {
1705: // nothing we can do here
1706: }
1707: // make sure that the timer does not keep on
1708: // displaying (we're not sure that the STOPPED
1709: // event will reach us before the VM becomes
1710: // suspended)
1711: stopDisplayTimer();
1712: // make sure to restart upon resume
1713: restartOnResume = true;
1714: } else {
1715: restartOnResume = false;
1716: }
1717: }
1718:
1719: /**
1720: * If the player was playing when the MIDlet was paused,
1721: * then the player will be restarted here.
1722: */
1723: public synchronized void resumeApp() {
1724: if (player != null && restartOnResume) {
1725: try {
1726: player.start();
1727: } catch (MediaException me) {
1728: error(me);
1729: }
1730: // player.start() will trigger the display timer
1731: // to be started, so we don't need to explicitely
1732: // call startDisplayTimer().
1733: }
1734: restartOnResume = false;
1735: }
1736:
1737: // ///////////////// INNER CLASSES /////////////////// //
1738:
1739: /**
1740: * Inner class for handling the query listener
1741: * when entering the recording URL
1742: */
1743: private class RecordTask implements Utils.QueryListener {
1744: private RecordTask() {
1745: }
1746:
1747: public void start(String location) {
1748: startRecording(location);
1749: }
1750:
1751: // interface Utils.QueryListener
1752: // used for entering the filename of a recording
1753: public void queryOK(String text) {
1754: start(text);
1755: }
1756:
1757: public void queryCancelled() {
1758: // don't do anything if query is cancelled.
1759: // the previous visible Displayable will be
1760: // displayed automatically
1761: }
1762:
1763: }
1764:
1765: /**
1766: * The timer task that will be called every timerInterval
1767: * milliseconds
1768: */
1769: private class SPTimerTask extends TimerTask {
1770: public void run() {
1771: updateTime();
1772: if (redisplayKaraokeCounter > 0) {
1773: redisplayKaraokeCounter--;
1774: if (redisplayKaraokeCounter == 0) {
1775: displayNextKaraokePhrase();
1776: }
1777: }
1778: if (changeSongDisplayCounter > 0
1779: && songDisplayNames.length > 0) {
1780: changeSongDisplayCounter--;
1781: if (changeSongDisplayCounter == 0) {
1782: currSongDisplay = (currSongDisplay + 1)
1783: % songDisplayNames.length;
1784: updateSongDisplay();
1785: changeSongDisplayCounter = SONG_DISPLAY_COUNTER;
1786: if (currSongDisplay == 0) {
1787: changeSongDisplayCounter *= 2;
1788: }
1789: }
1790: }
1791: }
1792: }
1793:
1794: // ////////////////// INNER INTERFACES ///////////////////// //
1795:
1796: /**
1797: * This interface is implemented by the Displayable
1798: * which uses this class. It provides the main screen.
1799: */
1800: interface Parent extends Utils.BreadCrumbTrail {
1801: public Utils.BreadCrumbTrail getParent();
1802:
1803: public String getTitle();
1804:
1805: // callbacks for display matters of the main player screen
1806: public void setupDisplay(); // called after the media is prefetched
1807:
1808: public void setStatus(String s);
1809:
1810: public void setFeedback(String s);
1811:
1812: public void setFileTitle(String s);
1813:
1814: public void updateKaraoke();
1815:
1816: public void updateTime();
1817:
1818: public void updateRate(); // and tempo
1819:
1820: public void updateDisplay();
1821:
1822: public void fullScreen(boolean value);
1823: }
1824: }
|