tonescanvas.java

来自「J2ME MIDP_Example_Applications」· Java 代码 · 共 297 行

JAVA
297
字号
// Copyright 2003 Nokia Corporation.
//
// THIS SOURCE CODE IS PROVIDED 'AS IS', WITH NO WARRANTIES WHATSOEVER,
// EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, FITNESS
// FOR ANY PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE
// OR TRADE PRACTICE, RELATING TO THE SOURCE CODE OR ANY WARRANTY OTHERWISE
// ARISING OUT OF ANY PROPOSAL, SPECIFICATION, OR SAMPLE AND WITH NO
// OBLIGATION OF NOKIA TO PROVIDE THE LICENSEE WITH ANY MAINTENANCE OR
// SUPPORT. FURTHERMORE, NOKIA MAKES NO WARRANTY THAT EXERCISE OF THE
// RIGHTS GRANTED HEREUNDER DOES NOT INFRINGE OR MAY NOT CAUSE INFRINGEMENT
// OF ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OWNED OR CONTROLLED
// BY THIRD PARTIES
//
// Furthermore, information provided in this source code is preliminary,
// and may be changed substantially prior to final release. Nokia Corporation
// retains the right to make changes to this source code at
// any time, without notice. This source code is provided for informational
// purposes only.
//
// Nokia and Nokia Connecting People are registered trademarks of Nokia
// Corporation.
// Java and all Java-based marks are trademarks or registered trademarks of
// Sun Microsystems, Inc.
// Other product and company names mentioned herein may be trademarks or
// trade names of their respective owners.
//
// A non-exclusive, non-transferable, worldwide, limited license is hereby
// granted to the Licensee to download, print, reproduce and modify the
// source code. The licensee has the right to market, sell, distribute and
// make available the source code in original or modified form only when
// incorporated into the programs developed by the Licensee. No other
// license, express or implied, by estoppel or otherwise, to any other
// intellectual property rights is granted herein.


package example.tones;

import javax.microedition.lcdui.*;


class TonesCanvas
    extends Canvas
    implements CommandListener
{
    // Constants and frequencies for tone playing
    private static final int SILENT = -1;  // rogue value for table index
    private static int frequencies[][] =
    {
        { 523,  554},         // C, C#
        { 587,  622},         // D, D#
        { 659,  659},         // E, E (there is no E#)
        { 698,  740},         // F, F#
        { 784,  831},         // G, G#
        { 880,  932},         // A, A#
        { 988,  988},         // B, B (there is no B#)
        {1047, 1109},         // C, C#
        {1175, 1245},         // D, D#
        {1319, 1319},         // E, E (there is no E#)
        {1397, 1480}          // F, F#
    };
    private static final int NATURAL = 0;
    private static final int SHARP = 1;

    // Constants for screen layout. Top of clef is highest point; bottom
    // of middle C note is lowest point. Clef will be drawn at screen left,
    // note at screen centre, possible sharp to left of note
    private static final int CLEF_G_LINE_Y = 30; // clef curls around 'G' line
    private static final int NOTE_WIDTH = 7;
    private static final int NOTE_HEIGHT = 7;
    private static final int SHARP_WIDTH = 5;
    private static final int LINE_SPACING = 6;
    private static final int TOP_LINE_Y = CLEF_G_LINE_Y - 3 * LINE_SPACING;
    private static final int MIDDLE_C_Y = TOP_LINE_Y + 5 * LINE_SPACING;
    private static final int LAYOUT_HEIGHT = MIDDLE_C_Y + NOTE_HEIGHT / 2 + 1;
    private static final int SHARP_OFFSET = SHARP_WIDTH + 2; // 2 for spacing
    private static final int LEGER_LINE_WIDTH = NOTE_WIDTH + 4;

    private final TonesMIDlet parent;
    private final Image trebleImg;
    private final Image noteImg;
    private final Image sharpImg;
    private final Command exitCommand;
    private final TonePlayer tonePlayer;

    private int note = SILENT;
    private int currentKey;
    private boolean sharp = false;


    TonesCanvas(TonesMIDlet parent)
    {
        this.parent = parent;
        trebleImg = createImage("/treble.png");
        noteImg   = createImage("/note.png");
        sharpImg  = createImage("/sharp.png");

        // create a NokiaTonePlayer if Nokia UI API is available,
        // otherwise a dummy TonePlayer
        tonePlayer = makeTonePlayer();

        exitCommand = new Command("Exit", Command.EXIT, 1);
        addCommand(exitCommand);

        setCommandListener(this);
    }


    public void paint(Graphics g)
    {
        int width = getWidth();
        int height = getHeight();
        g.setColor(0x00FFFFFF);   // white
        g.fillRect(0, 0, width, height);

        int topOffset = (getHeight() - LAYOUT_HEIGHT) / 2;

        // draw treble clef, 1 pixel in from left edge
        g.drawImage(trebleImg, 1, topOffset, Graphics.TOP | Graphics.LEFT);

        if (note != SILENT)
        {
            // draw note
            drawNote(g, topOffset, width);
        }

        drawLines(g, topOffset, width);
    }


    // draw the five horizontal lines of the music score
    private void drawLines(Graphics g, int topOffset, int width)
    {
        g.setColor(0x00000000);   // black
        for (int i = 0; i < 5; ++i)
        {
            int y = topOffset + TOP_LINE_Y + LINE_SPACING * i;
            g.drawLine(0, y, width-1, y);
        }
    }


    private void drawNote(Graphics g, int offset, int width)
    {
        int y = offset + MIDDLE_C_Y - note * LINE_SPACING / 2;
        int x = width / 2;
        g.drawImage(noteImg, x, y, Graphics.HCENTER | Graphics.VCENTER);

        // this next bit should be made more smart if it ever
        // needs to be more general
        if (note == 0)   // C should have a 'leger line' through it
        {
            g.setColor(0x00000000);   // black
            g.drawLine(x-LEGER_LINE_WIDTH/2, y, x+LEGER_LINE_WIDTH/2, y);
        }

        // is sharp set, and can this note be sharp (E & B can't)
        if (sharp &&
            (frequencies[note][NATURAL] != frequencies[note][SHARP]))
        {
            g.drawImage(sharpImg, x - SHARP_OFFSET, y,
                        Graphics.HCENTER | Graphics.VCENTER);
        }
    }


    public void commandAction(Command c, Displayable d)
    {
        if (c == exitCommand)
        {
            parent.exitRequested();
        }
    }


    public void keyPressed(int keyCode)
    {
        if (keyCode == Canvas.KEY_POUND)
        {
            sharp = !sharp;    // toggle sharp state
        }
        else
        {
            switch (keyCode)
            {
            case Canvas.KEY_NUM1:
                note = 0;   // middle C
                break;
            case Canvas.KEY_NUM2:
                note = 1;   // D
                break;
            case Canvas.KEY_NUM3:
                note = 2;   // E
                break;
            case Canvas.KEY_NUM4:
                note = 3;   // F
                break;
            case Canvas.KEY_NUM5:
                note = 4;   // G
                break;
            case Canvas.KEY_NUM6:
                note = 5;   // A
                break;
            case Canvas.KEY_NUM7:
                note = 6;   // B
                break;
            case Canvas.KEY_NUM8:
                note = 7;   // C
                break;
            case Canvas.KEY_NUM9:
                note = 8;   // D
                break;
            case Canvas.KEY_STAR:
                note = 9;   // E
                break;
            case Canvas.KEY_NUM0:
                note = 10;  // F
                break;
            default:
                note = SILENT;
                break;
            }

            if (note != SILENT)
            {
                startNote();
            }
            currentKey = keyCode;
        }
        repaint();
    }


    public void keyReleased(int keyCode)
    {
        // This check deals with the possibility that we have this sequence:
        //   key A pressed; ...; key B pressed; key A released
        // The user will expect that the tone for key B continues playing.
        if (keyCode == currentKey)
        {
            note = SILENT;
            stopNote();
        }
        repaint();
    }


    private void startNote()
    {
        tonePlayer.play(frequencies[note][sharp ? SHARP : NATURAL]);
    }


    void stopNote()
    {
        tonePlayer.stop();
    }


    private static Image createImage(String filename)
    {
        Image image = null;
        try
        {
            image = Image.createImage(filename);
        }
        catch (java.io.IOException e)
        {
            // just let return value be null
        }
        return image;
    }


    private static TonePlayer makeTonePlayer()
    {
        TonePlayer player;

        try
        {
            // This statement throws an exception if no Nokia UI API available
            Class.forName("com.nokia.mid.sound.Sound");
            // If we get here, Nokia UI API is available, so we can safely
            // create a player that uses it. But we use Class.forName rather
            // than 'new' so that there is no link dependency.
            Class clas = Class.forName("example.tones.NokiaTonePlayer");
            player = (TonePlayer)(clas.newInstance());
        }
        catch (Exception e)
        {
            // If no Nokia UI API, then create a dummy tone player
            player = new TonePlayer();
        }

        return player;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?