www.pudn.com > AudioSamples1.rar > BallCanvas.java


/*
 *
 * Copyright (c) 2007, Sun Microsystems, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Sun Microsystems nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package example.audiodemo;

import java.io.InputStream;

import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;


public class BallCanvas extends Canvas implements CommandListener {
    private BBall midlet;
    private Player player;
    private int[] notes = { 68, 72, 70, 74, 76, 80, 56, 58 };
    private int[] colors =
        { 0xff, 0xff00, 0xff0000, 0xffff, 0xff00ff, 0xff8080, 0x80ff80, 0x8080ff };

    // a set of free roaming balls
    private SmallBall[] balls;
    private int numBalls;
    private int width;
    private int height;
    private boolean paused;
    private Command backCommand = new Command("Back", Command.BACK, 1);
    private Command pauseCommand = new Command("Pause", Command.BACK, 1);
    private Command playCommand = new Command("Play", Command.BACK, 1);
    private boolean playerCreated;
    private int currBackground = -1;

    public BallCanvas(BBall parentMidlet) {
        midlet = parentMidlet;

        width = getWidth();
        height = getHeight();

        balls = null;
        numBalls = 0;
        paused = true;

        this.addCommand(backCommand);
        this.addCommand(pauseCommand);
        setCommandListener(this);
    }

    public synchronized void init(int maxBalls, int bg) {
        if (maxBalls < 1) {
            maxBalls = 1;
        } else if (maxBalls > notes.length) {
            maxBalls = notes.length;
        }

        if ((balls == null) || (player == null) || (balls.length != maxBalls) ||
                (currBackground != bg)) {
            destroy();
            // initialize the array of balls
            balls = new SmallBall[maxBalls];

            currBackground = bg;
            playerCreated = initPlayer(bg);
        }

        numBalls = 0;
        pause();

        // Start with 2 balls
        makeNumberOfBalls(2);
    }

    boolean needAlert() {
        return (!playerCreated);
    }

    private static String guessContentType(String url)
        throws Exception {
        String ctype;

        // some simple test for the content type
        if (url.endsWith("wav")) {
            ctype = "audio/x-wav";
        } else if (url.endsWith("jts")) {
            ctype = "audio/x-tone-seq";
        } else if (url.endsWith("mid")) {
            ctype = "audio/midi";
        } else {
            throw new Exception("Cannot guess content type from URL: " + url);
        }

        return ctype;
    }

    private void createPlayer(String url) throws Exception {
        if (url.startsWith("resource")) {
            int idx = url.indexOf(':');
            String loc = url.substring(idx + 1);
            InputStream is = getClass().getResourceAsStream(loc);
            String ctype = guessContentType(url);
            player = Manager.createPlayer(is, ctype);
        } else {
            player = Manager.createPlayer(url);
        }
    }

    private boolean initPlayer(int bg) {
        try {
            switch (bg) {
            case 1: // wave bg
                createPlayer(midlet.wavbgUrl);

                break;

            case 2: // tone seq bg
             {
                byte d = 8;
                byte C4 = ToneControl.C4;
                byte D4 = ToneControl.C4 + 2; // a whole step
                byte E4 = ToneControl.C4 + 4; // a major third
                byte G4 = ToneControl.C4 + 7; // a fifth
                byte rest = ToneControl.SILENCE; // eighth-note rest

                byte[] mySequence =
                    new byte[] {
                        ToneControl.VERSION, 1, ToneControl.TEMPO, 30, ToneControl.BLOCK_START, 0,
                        E4, d, D4, d, C4, d, D4, d, E4, d, E4, d, E4, d, rest, d,
                        ToneControl.BLOCK_END, 0, ToneControl.PLAY_BLOCK, 0, D4, d, D4, d, D4, d,
                        rest, d, E4, d, G4, d, G4, d, rest, d, //play "B" section
                        ToneControl.PLAY_BLOCK, 0, // content of "A" section
                        D4, d, D4, d, E4, d, D4, d, C4, d, rest, d // play "C" section
                    };
                player = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
                player.realize();

                ToneControl c = (ToneControl)player.getControl("ToneControl");
                c.setSequence(mySequence);
            }

            break;

            case 3: // MIDI bg
                createPlayer(midlet.midbgUrl);

                break;

            default:
                player = null;
            }

            if (player != null) {
                player.setLoopCount(-1);
                player.start();
            }
        } catch (Exception ex) {
            ex.printStackTrace();

            if (player != null) {
                player.close();
            }

            player = null;

            return false;
        }

        return true;
    }

    /**
     * Draws the drawing frame (which also contains the ball) and the
     * controls.
     */
    protected void paint(Graphics g) {
        int x = g.getClipX();
        int y = g.getClipY();
        int w = g.getClipWidth();
        int h = g.getClipHeight();

        // Draw the frame 
        g.setColor(0xffffff);
        g.fillRect(x, y, w, h);

        // Draw each ball
        for (int i = 0; i < numBalls; i++) {
            if (balls[i] != null) {
                balls[i].paint(g);
            }
        }

        g.setColor(0);
        g.drawRect(0, 0, width - 1, height - 1);
    }

    private void makeNumberOfBalls(int newNum) {
        if (balls != null) {
            if (newNum > balls.length) {
                newNum = balls.length;
            } else if (newNum < 1) {
                newNum = 1;
            }

            if (newNum != numBalls) {
                // temporarily disable painting
                numBalls = 0;

                // first create newNum balls, if necessary
                for (int i = 0; i < newNum; i++) {
                    if (balls[i] == null) {
                        balls[i] = new SmallBall(this, 0, 0, width, height);
                        balls[i].setNote(notes[i]);
                        balls[i].setColor(colors[i]);
                    }

                    if (!paused && balls[i].stop) {
                        balls[i].stop = false;
                        (new Thread(balls[i])).start();
                    }
                }

                // then destroy any other balls
                for (int i = newNum; i < balls.length; i++) {
                    if (balls[i] != null) {
                        // stop the thread and remove the reference to it
                        balls[i].stop = true;
                        balls[i] = null;
                    }
                }

                // enable painting
                numBalls = newNum;

                if (newNum > 0) {
                    balls[0].doRepaint = true;
                }
            }
        }
    }

    /**
     * Destroy
     */
    synchronized void destroy() {
        // kill all the balls and terminate
        numBalls = 0;
        pause();
        balls = null;

        if (player != null) {
            player.close();
            player = null;
        }
    }

    /*
     * Return whether the canvas is paused or not.
     */
    boolean isPaused() {
        return paused;
    }

    /**
     * Pause the balls by signaling each of them to stop.
     * The ball object still exists and holds the current position
     * of the ball.  It may be restarted later.
     * the current thread will be terminated.
     */
    void pause() {
        if (!paused) {
            synchronized (this) {
                paused = true;

                for (int i = 0; i < balls.length; i++) {
                    if (balls[i] != null) {
                        balls[i].stop = true;
                    }
                }

                try {
                    if (player != null) {
                        player.stop();
                    }
                } catch (MediaException e) {
                    // There's nothing much we can do here.
                }
            }

            repaint();
        }
    }

    /*
     * Start creates a new thread for each ball and start it.
     */
    void start() {
        if (paused) {
            synchronized (this) {
                paused = false;

                if (balls != null) {
                    for (int i = 0; i < balls.length; i++) {
                        if (balls[i] != null) {
                            balls[i].stop = false;
                            (new Thread(balls[i])).start();
                        }
                    }
                }

                if (player != null) {
                    try {
                        player.start();
                    } catch (Exception ex) {
                    }
                }
            }

            repaint();
        }
    }

    public void commandAction(Command c, Displayable s) {
        if (c == backCommand) {
            destroy();
            midlet.displayList();
        } else if (c == pauseCommand) {
            pause();
            removeCommand(pauseCommand);
            addCommand(playCommand);
        } else if (c == playCommand) {
            removeCommand(playCommand);
            addCommand(pauseCommand);
            start();
        }
    }

    /**
     * Handle a pen down event.
     */
    public void keyPressed(int keyCode) {
        int action = getGameAction(keyCode);

        switch (action) {
        case LEFT:
            // Reduce the number of threads
            makeNumberOfBalls(numBalls - 1);

            break;

        case RIGHT:
            // Increase the number of threads
            makeNumberOfBalls(numBalls + 1);

            break;

        case UP:
            // Make them move faster
            SmallBall.faster();

            break;

        case DOWN:
            // Make them move slower
            SmallBall.slower();

            break;
        }

        repaint();
    }
}