1 /* 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sound.midi; 27 28 29 /** 30 * A <code>MetaMessage</code> is a <code>{@link MidiMessage}</code> that is not meaningful to synthesizers, but 31 * that can be stored in a MIDI file and interpreted by a sequencer program. 32 * (See the discussion in the <code>MidiMessage</code> 33 * class description.) The Standard MIDI Files specification defines 34 * various types of meta-events, such as sequence number, lyric, cue point, 35 * and set tempo. There are also meta-events 36 * for such information as lyrics, copyrights, tempo indications, time and key 37 * signatures, markers, etc. For more information, see the Standard MIDI Files 1.0 38 * specification, which is part of the Complete MIDI 1.0 Detailed Specification 39 * published by the MIDI Manufacturer's Association 40 * (<a href = http://www.midi.org>http://www.midi.org</a>). 41 * 42 * <p> 43 * When data is being transported using MIDI wire protocol, 44 * a <code>{@link ShortMessage}</code> with the status value <code>0xFF</code> represents 45 * a system reset message. In MIDI files, this same status value denotes a <code>MetaMessage</code>. 46 * The types of meta-message are distinguished from each other by the first byte 47 * that follows the status byte <code>0xFF</code>. The subsequent bytes are data 48 * bytes. As with system exclusive messages, there are an arbitrary number of 49 * data bytes, depending on the type of <code>MetaMessage</code>. 50 * 51 * @see MetaEventListener 52 * 53 * @author David Rivas 54 * @author Kara Kytle 55 */ 56 57 public class MetaMessage extends MidiMessage { 58 59 60 // Status byte defines 61 62 /** 63 * Status byte for <code>MetaMessage</code> (0xFF, or 255), which is used 64 * in MIDI files. It has the same value as SYSTEM_RESET, which 65 * is used in the real-time "MIDI wire" protocol. 66 * @see MidiMessage#getStatus 67 */ 68 public static final int META = 0xFF; // 255 69 70 // Instance variables 71 72 /** 73 * The length of the actual message in the data array. 74 * This is used to determine how many bytes of the data array 75 * is the message, and how many are the status byte, the 76 * type byte, and the variable-length-int describing the 77 * length of the message. 78 */ 79 private int dataLength = 0; 80 81 82 /** 83 * Constructs a new <code>MetaMessage</code>. The contents of 84 * the message are not set here; use 85 * {@link #setMessage(int, byte[], int) setMessage} 86 * to set them subsequently. 87 */ 88 public MetaMessage() { 89 // Default meta message data: just the META status byte value 90 this(new byte[]{(byte) META, 0}); 91 } 92 93 /** 94 * Constructs a new {@code MetaMessage} and sets the message parameters. 95 * The contents of the message can be changed by using 96 * the {@code setMessage} method. 97 * 98 * @param type meta-message type (must be less than 128) 99 * @param data the data bytes in the MIDI message 100 * @param length an amount of bytes in the {@code data} byte array; 101 * it should be non-negative and less than or equal to 102 * {@code data.length} 103 * @throws InvalidMidiDataException if the parameter values do not specify 104 * a valid MIDI meta message 105 * @see #setMessage(int, byte[], int) 106 * @see #getType() 107 * @see #getData() 108 * @since 1.7 109 */ 110 public MetaMessage(int type, byte[] data, int length) 111 throws InvalidMidiDataException { 112 super(null); 113 setMessage(type, data, length); // can throw InvalidMidiDataException 114 } 115 116 117 /** 118 * Constructs a new <code>MetaMessage</code>. 119 * @param data an array of bytes containing the complete message. 120 * The message data may be changed using the <code>setMessage</code> 121 * method. 122 * @see #setMessage 123 */ 124 protected MetaMessage(byte[] data) { 125 super(data); 126 //$$fb 2001-10-06: need to calculate dataLength. Fix for bug #4511796 127 if (data.length>=3) { 128 dataLength=data.length-3; 129 int pos=2; 130 while (pos<data.length && (data[pos] & 0x80)!=0) { 131 dataLength--; pos++; 132 } 133 } 134 } 135 136 137 /** 138 * Sets the message parameters for a <code>MetaMessage</code>. 139 * Since only one status byte value, <code>0xFF</code>, is allowed for meta-messages, 140 * it does not need to be specified here. Calls to <code>{@link MidiMessage#getStatus getStatus}</code> return 141 * <code>0xFF</code> for all meta-messages. 142 * <p> 143 * The <code>type</code> argument should be a valid value for the byte that 144 * follows the status byte in the <code>MetaMessage</code>. The <code>data</code> argument 145 * should contain all the subsequent bytes of the <code>MetaMessage</code>. In other words, 146 * the byte that specifies the type of <code>MetaMessage</code> is not considered a data byte. 147 * 148 * @param type meta-message type (must be less than 128) 149 * @param data the data bytes in the MIDI message 150 * @param length the number of bytes in the <code>data</code> 151 * byte array 152 * @throws <code>InvalidMidiDataException</code> if the 153 * parameter values do not specify a valid MIDI meta message 154 */ 155 public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException { 156 157 if (type >= 128 || type < 0) { 158 throw new InvalidMidiDataException("Invalid meta event with type " + type); 159 } 160 if ((length > 0 && length > data.length) || length < 0) { 161 throw new InvalidMidiDataException("length out of bounds: "+length); 162 } 163 164 this.length = 2 + getVarIntLength(length) + length; 165 this.dataLength = length; 166 this.data = new byte[this.length]; 167 this.data[0] = (byte) META; // status value for MetaMessages (meta events) 168 this.data[1] = (byte) type; // MetaMessage type 169 writeVarInt(this.data, 2, length); // write the length as a variable int 170 if (length > 0) { 171 System.arraycopy(data, 0, this.data, this.length - this.dataLength, this.dataLength); 172 } 173 } 174 175 176 /** 177 * Obtains the type of the <code>MetaMessage</code>. 178 * @return an integer representing the <code>MetaMessage</code> type 179 */ 180 public int getType() { 181 if (length>=2) { 182 return data[1] & 0xFF; 183 } 184 return 0; 185 } 186 187 188 189 /** 190 * Obtains a copy of the data for the meta message. The returned 191 * array of bytes does not include the status byte or the message 192 * length data. The length of the data for the meta message is 193 * the length of the array. Note that the length of the entire 194 * message includes the status byte and the meta message type 195 * byte, and therefore may be longer than the returned array. 196 * @return array containing the meta message data. 197 * @see MidiMessage#getLength 198 */ 199 public byte[] getData() { 200 byte[] returnedArray = new byte[dataLength]; 201 System.arraycopy(data, (length - dataLength), returnedArray, 0, dataLength); 202 return returnedArray; 203 } 204 205 206 /** 207 * Creates a new object of the same class and with the same contents 208 * as this object. 209 * @return a clone of this instance 210 */ 211 public Object clone() { 212 byte[] newData = new byte[length]; 213 System.arraycopy(data, 0, newData, 0, newData.length); 214 215 MetaMessage event = new MetaMessage(newData); 216 return event; 217 } 218 219 // HELPER METHODS 220 221 private int getVarIntLength(long value) { 222 int length = 0; 223 do { 224 value = value >> 7; 225 length++; 226 } while (value > 0); 227 return length; 228 } 229 230 private final static long mask = 0x7F; 231 232 private void writeVarInt(byte[] data, int off, long value) { 233 int shift=63; // number of bitwise left-shifts of mask 234 // first screen out leading zeros 235 while ((shift > 0) && ((value & (mask << shift)) == 0)) shift-=7; 236 // then write actual values 237 while (shift > 0) { 238 data[off++]=(byte) (((value & (mask << shift)) >> shift) | 0x80); 239 shift-=7; 240 } 241 data[off] = (byte) (value & mask); 242 } 243 244 }