jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java
changeset 25859 3317bb8137f4
parent 19207 3448b0cb4077
child 26037 508779ce6619
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java	Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.sound.midi;
+
+
+/**
+ * A <code>MetaMessage</code> is a <code>{@link MidiMessage}</code> that is not meaningful to synthesizers, but
+ * that can be stored in a MIDI file and interpreted by a sequencer program.
+ * (See the discussion in the <code>MidiMessage</code>
+ * class description.)  The Standard MIDI Files specification defines
+ * various types of meta-events, such as sequence number, lyric, cue point,
+ * and set tempo.  There are also meta-events
+ * for such information as lyrics, copyrights, tempo indications, time and key
+ * signatures, markers, etc.  For more information, see the Standard MIDI Files 1.0
+ * specification, which is part of the Complete MIDI 1.0 Detailed Specification
+ * published by the MIDI Manufacturer's Association
+ * (<a href = http://www.midi.org>http://www.midi.org</a>).
+ *
+ * <p>
+ * When data is being transported using MIDI wire protocol,
+ * a <code>{@link ShortMessage}</code> with the status value <code>0xFF</code> represents
+ * a system reset message.  In MIDI files, this same status value denotes a <code>MetaMessage</code>.
+ * The types of meta-message are distinguished from each other by the first byte
+ * that follows the status byte <code>0xFF</code>.  The subsequent bytes are data
+ * bytes.  As with system exclusive messages, there are an arbitrary number of
+ * data bytes, depending on the type of <code>MetaMessage</code>.
+ *
+ * @see MetaEventListener
+ *
+ * @author David Rivas
+ * @author Kara Kytle
+ */
+
+public class MetaMessage extends MidiMessage {
+
+
+    // Status byte defines
+
+    /**
+     * Status byte for <code>MetaMessage</code> (0xFF, or 255), which is used
+     * in MIDI files.  It has the same value as SYSTEM_RESET, which
+     * is used in the real-time "MIDI wire" protocol.
+     * @see MidiMessage#getStatus
+     */
+    public static final int META                                                = 0xFF; // 255
+
+    // Instance variables
+
+    /**
+     * The length of the actual message in the data array.
+     * This is used to determine how many bytes of the data array
+     * is the message, and how many are the status byte, the
+     * type byte, and the variable-length-int describing the
+     * length of the message.
+     */
+    private int dataLength = 0;
+
+
+    /**
+     * Constructs a new <code>MetaMessage</code>. The contents of
+     * the message are not set here; use
+     * {@link #setMessage(int, byte[], int) setMessage}
+     * to set them subsequently.
+     */
+    public MetaMessage() {
+        // Default meta message data: just the META status byte value
+        this(new byte[]{(byte) META, 0});
+    }
+
+    /**
+     * Constructs a new {@code MetaMessage} and sets the message parameters.
+     * The contents of the message can be changed by using
+     * the {@code setMessage} method.
+     *
+     * @param type   meta-message type (must be less than 128)
+     * @param data   the data bytes in the MIDI message
+     * @param length an amount of bytes in the {@code data} byte array;
+     *     it should be non-negative and less than or equal to
+     *     {@code data.length}
+     * @throws InvalidMidiDataException if the parameter values do not specify
+     *     a valid MIDI meta message
+     * @see #setMessage(int, byte[], int)
+     * @see #getType()
+     * @see #getData()
+     * @since 1.7
+     */
+    public MetaMessage(int type, byte[] data, int length)
+            throws InvalidMidiDataException {
+        super(null);
+        setMessage(type, data, length); // can throw InvalidMidiDataException
+    }
+
+
+    /**
+     * Constructs a new <code>MetaMessage</code>.
+     * @param data an array of bytes containing the complete message.
+     * The message data may be changed using the <code>setMessage</code>
+     * method.
+     * @see #setMessage
+     */
+    protected MetaMessage(byte[] data) {
+        super(data);
+        //$$fb 2001-10-06: need to calculate dataLength. Fix for bug #4511796
+        if (data.length>=3) {
+            dataLength=data.length-3;
+            int pos=2;
+            while (pos<data.length && (data[pos] & 0x80)!=0) {
+                dataLength--; pos++;
+            }
+        }
+    }
+
+
+    /**
+     * Sets the message parameters for a <code>MetaMessage</code>.
+     * Since only one status byte value, <code>0xFF</code>, is allowed for meta-messages,
+     * it does not need to be specified here.  Calls to <code>{@link MidiMessage#getStatus getStatus}</code> return
+     * <code>0xFF</code> for all meta-messages.
+     * <p>
+     * The <code>type</code> argument should be a valid value for the byte that
+     * follows the status byte in the <code>MetaMessage</code>.  The <code>data</code> argument
+     * should contain all the subsequent bytes of the <code>MetaMessage</code>.  In other words,
+     * the byte that specifies the type of <code>MetaMessage</code> is not considered a data byte.
+     *
+     * @param type              meta-message type (must be less than 128)
+     * @param data              the data bytes in the MIDI message
+     * @param length    the number of bytes in the <code>data</code>
+     * byte array
+     * @throws                  InvalidMidiDataException  if the
+     * parameter values do not specify a valid MIDI meta message
+     */
+    public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
+
+        if (type >= 128 || type < 0) {
+            throw new InvalidMidiDataException("Invalid meta event with type " + type);
+        }
+        if ((length > 0 && length > data.length) || length < 0) {
+            throw new InvalidMidiDataException("length out of bounds: "+length);
+        }
+
+        this.length = 2 + getVarIntLength(length) + length;
+        this.dataLength = length;
+        this.data = new byte[this.length];
+        this.data[0] = (byte) META;        // status value for MetaMessages (meta events)
+        this.data[1] = (byte) type;        // MetaMessage type
+        writeVarInt(this.data, 2, length); // write the length as a variable int
+        if (length > 0) {
+            System.arraycopy(data, 0, this.data, this.length - this.dataLength, this.dataLength);
+        }
+    }
+
+
+    /**
+     * Obtains the type of the <code>MetaMessage</code>.
+     * @return an integer representing the <code>MetaMessage</code> type
+     */
+    public int getType() {
+        if (length>=2) {
+            return data[1] & 0xFF;
+        }
+        return 0;
+    }
+
+
+
+    /**
+     * Obtains a copy of the data for the meta message.  The returned
+     * array of bytes does not include the status byte or the message
+     * length data.  The length of the data for the meta message is
+     * the length of the array.  Note that the length of the entire
+     * message includes the status byte and the meta message type
+     * byte, and therefore may be longer than the returned array.
+     * @return array containing the meta message data.
+     * @see MidiMessage#getLength
+     */
+    public byte[] getData() {
+        byte[] returnedArray = new byte[dataLength];
+        System.arraycopy(data, (length - dataLength), returnedArray, 0, dataLength);
+        return returnedArray;
+    }
+
+
+    /**
+     * Creates a new object of the same class and with the same contents
+     * as this object.
+     * @return a clone of this instance
+     */
+    public Object clone() {
+        byte[] newData = new byte[length];
+        System.arraycopy(data, 0, newData, 0, newData.length);
+
+        MetaMessage event = new MetaMessage(newData);
+        return event;
+    }
+
+    // HELPER METHODS
+
+    private int getVarIntLength(long value) {
+        int length = 0;
+        do {
+            value = value >> 7;
+            length++;
+        } while (value > 0);
+        return length;
+    }
+
+    private final static long mask = 0x7F;
+
+    private void writeVarInt(byte[] data, int off, long value) {
+        int shift=63; // number of bitwise left-shifts of mask
+        // first screen out leading zeros
+        while ((shift > 0) && ((value & (mask << shift)) == 0)) shift-=7;
+        // then write actual values
+        while (shift > 0) {
+            data[off++]=(byte) (((value & (mask << shift)) >> shift) | 0x80);
+            shift-=7;
+        }
+        data[off] = (byte) (value & mask);
+    }
+
+}