001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.audiodemo;
033:
034: import java.io.InputStream;
035:
036: import javax.microedition.lcdui.*;
037: import javax.microedition.media.*;
038: import javax.microedition.media.control.*;
039:
040: public class BallCanvas extends Canvas implements CommandListener {
041: private BBall midlet;
042: private Player player;
043: private int[] notes = { 68, 72, 70, 74, 76, 80, 56, 58 };
044: private int[] colors = { 0xff, 0xff00, 0xff0000, 0xffff, 0xff00ff,
045: 0xff8080, 0x80ff80, 0x8080ff };
046:
047: // a set of free roaming balls
048: private SmallBall[] balls;
049: private int numBalls;
050: private int width;
051: private int height;
052: private boolean paused;
053: private Command backCommand = new Command("Back", Command.BACK, 1);
054: private Command pauseCommand = new Command("Pause", Command.BACK, 1);
055: private Command playCommand = new Command("Play", Command.BACK, 1);
056: private boolean playerCreated;
057: private int currBackground = -1;
058:
059: public BallCanvas(BBall parentMidlet) {
060: midlet = parentMidlet;
061:
062: width = getWidth();
063: height = getHeight();
064:
065: balls = null;
066: numBalls = 0;
067: paused = true;
068:
069: this .addCommand(backCommand);
070: this .addCommand(pauseCommand);
071: setCommandListener(this );
072: }
073:
074: public synchronized void init(int maxBalls, int bg) {
075: if (maxBalls < 1) {
076: maxBalls = 1;
077: } else if (maxBalls > notes.length) {
078: maxBalls = notes.length;
079: }
080:
081: if ((balls == null) || (player == null)
082: || (balls.length != maxBalls) || (currBackground != bg)) {
083: destroy();
084: // initialize the array of balls
085: balls = new SmallBall[maxBalls];
086:
087: currBackground = bg;
088: playerCreated = initPlayer(bg);
089: }
090:
091: numBalls = 0;
092: pause();
093:
094: // Start with 2 balls
095: makeNumberOfBalls(2);
096: }
097:
098: boolean needAlert() {
099: return (!playerCreated);
100: }
101:
102: private static String guessContentType(String url) throws Exception {
103: String ctype;
104:
105: // some simple test for the content type
106: if (url.endsWith("wav")) {
107: ctype = "audio/x-wav";
108: } else if (url.endsWith("jts")) {
109: ctype = "audio/x-tone-seq";
110: } else if (url.endsWith("mid")) {
111: ctype = "audio/midi";
112: } else {
113: throw new Exception("Cannot guess content type from URL: "
114: + url);
115: }
116:
117: return ctype;
118: }
119:
120: private void createPlayer(String url) throws Exception {
121: if (url.startsWith("resource")) {
122: int idx = url.indexOf(':');
123: String loc = url.substring(idx + 1);
124: InputStream is = getClass().getResourceAsStream(loc);
125: String ctype = guessContentType(url);
126: player = Manager.createPlayer(is, ctype);
127: } else {
128: player = Manager.createPlayer(url);
129: }
130: }
131:
132: private boolean initPlayer(int bg) {
133: try {
134: switch (bg) {
135: case 1: // wave bg
136: createPlayer(midlet.wavbgUrl);
137:
138: break;
139:
140: case 2: // tone seq bg
141: {
142: byte d = 8;
143: byte C4 = ToneControl.C4;
144: byte D4 = ToneControl.C4 + 2; // a whole step
145: byte E4 = ToneControl.C4 + 4; // a major third
146: byte G4 = ToneControl.C4 + 7; // a fifth
147: byte rest = ToneControl.SILENCE; // eighth-note rest
148:
149: byte[] mySequence = new byte[] { ToneControl.VERSION,
150: 1, ToneControl.TEMPO, 30,
151: ToneControl.BLOCK_START, 0, E4, d, D4, d, C4,
152: d, D4, d, E4, d, E4, d, E4, d, rest, d,
153: ToneControl.BLOCK_END, 0,
154: ToneControl.PLAY_BLOCK, 0, D4, d, D4, d, D4, d,
155: rest, d, E4, d, G4, d, G4, d, rest, d, //play "B" section
156: ToneControl.PLAY_BLOCK, 0, // content of "A" section
157: D4, d, D4, d, E4, d, D4, d, C4, d, rest, d // play "C" section
158: };
159: player = Manager
160: .createPlayer(Manager.TONE_DEVICE_LOCATOR);
161: player.realize();
162:
163: ToneControl c = (ToneControl) player
164: .getControl("ToneControl");
165: c.setSequence(mySequence);
166: }
167:
168: break;
169:
170: case 3: // MIDI bg
171: createPlayer(midlet.midbgUrl);
172:
173: break;
174:
175: default:
176: player = null;
177: }
178:
179: if (player != null) {
180: player.setLoopCount(-1);
181: player.start();
182: }
183: } catch (Exception ex) {
184: ex.printStackTrace();
185:
186: if (player != null) {
187: player.close();
188: }
189:
190: player = null;
191:
192: return false;
193: }
194:
195: return true;
196: }
197:
198: /**
199: * Draws the drawing frame (which also contains the ball) and the
200: * controls.
201: */
202: protected void paint(Graphics g) {
203: int x = g.getClipX();
204: int y = g.getClipY();
205: int w = g.getClipWidth();
206: int h = g.getClipHeight();
207:
208: // Draw the frame
209: g.setColor(0xffffff);
210: g.fillRect(x, y, w, h);
211:
212: // Draw each ball
213: for (int i = 0; i < numBalls; i++) {
214: if (balls[i] != null) {
215: balls[i].paint(g);
216: }
217: }
218:
219: g.setColor(0);
220: g.drawRect(0, 0, width - 1, height - 1);
221: }
222:
223: private void makeNumberOfBalls(int newNum) {
224: if (balls != null) {
225: if (newNum > balls.length) {
226: newNum = balls.length;
227: } else if (newNum < 1) {
228: newNum = 1;
229: }
230:
231: if (newNum != numBalls) {
232: // temporarily disable painting
233: numBalls = 0;
234:
235: // first create newNum balls, if necessary
236: for (int i = 0; i < newNum; i++) {
237: if (balls[i] == null) {
238: balls[i] = new SmallBall(this , 0, 0, width,
239: height);
240: balls[i].setNote(notes[i]);
241: balls[i].setColor(colors[i]);
242: }
243:
244: if (!paused && balls[i].stop) {
245: balls[i].stop = false;
246: (new Thread(balls[i])).start();
247: }
248: }
249:
250: // then destroy any other balls
251: for (int i = newNum; i < balls.length; i++) {
252: if (balls[i] != null) {
253: // stop the thread and remove the reference to it
254: balls[i].stop = true;
255: balls[i] = null;
256: }
257: }
258:
259: // enable painting
260: numBalls = newNum;
261:
262: if (newNum > 0) {
263: balls[0].doRepaint = true;
264: }
265: }
266: }
267: }
268:
269: /**
270: * Destroy
271: */
272: synchronized void destroy() {
273: // kill all the balls and terminate
274: numBalls = 0;
275: pause();
276: balls = null;
277:
278: if (player != null) {
279: player.close();
280: player = null;
281: }
282: }
283:
284: /*
285: * Return whether the canvas is paused or not.
286: */
287: boolean isPaused() {
288: return paused;
289: }
290:
291: /**
292: * Pause the balls by signaling each of them to stop.
293: * The ball object still exists and holds the current position
294: * of the ball. It may be restarted later.
295: * the current thread will be terminated.
296: */
297: void pause() {
298: if (!paused) {
299: synchronized (this ) {
300: paused = true;
301:
302: for (int i = 0; i < balls.length; i++) {
303: if (balls[i] != null) {
304: balls[i].stop = true;
305: }
306: }
307:
308: try {
309: if (player != null) {
310: player.stop();
311: }
312: } catch (MediaException e) {
313: // There's nothing much we can do here.
314: }
315: }
316:
317: repaint();
318: }
319: }
320:
321: /*
322: * Start creates a new thread for each ball and start it.
323: */
324: void start() {
325: if (paused) {
326: synchronized (this ) {
327: paused = false;
328:
329: if (balls != null) {
330: for (int i = 0; i < balls.length; i++) {
331: if (balls[i] != null) {
332: balls[i].stop = false;
333: (new Thread(balls[i])).start();
334: }
335: }
336: }
337:
338: if (player != null) {
339: try {
340: player.start();
341: } catch (Exception ex) {
342: }
343: }
344: }
345:
346: repaint();
347: }
348: }
349:
350: public void commandAction(Command c, Displayable s) {
351: if (c == backCommand) {
352: destroy();
353: midlet.displayList();
354: } else if (c == pauseCommand) {
355: pause();
356: removeCommand(pauseCommand);
357: addCommand(playCommand);
358: } else if (c == playCommand) {
359: removeCommand(playCommand);
360: addCommand(pauseCommand);
361: start();
362: }
363: }
364:
365: /**
366: * Handle a pen down event.
367: */
368: public void keyPressed(int keyCode) {
369: int action = getGameAction(keyCode);
370:
371: switch (action) {
372: case LEFT:
373: // Reduce the number of threads
374: makeNumberOfBalls(numBalls - 1);
375:
376: break;
377:
378: case RIGHT:
379: // Increase the number of threads
380: makeNumberOfBalls(numBalls + 1);
381:
382: break;
383:
384: case UP:
385: // Make them move faster
386: SmallBall.faster();
387:
388: break;
389:
390: case DOWN:
391: // Make them move slower
392: SmallBall.slower();
393:
394: break;
395: }
396:
397: repaint();
398: }
399: }
|