1 /* 2 * Copyright (c) 1998, 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 * A <code>SysexMessage</code> object represents a MIDI system exclusive message. 30 * <p> 31 * When a system exclusive message is read from a MIDI file, it always has 32 * a defined length. Data from a system exclusive message from a MIDI file 33 * should be stored in the data array of a <code>SysexMessage</code> as 34 * follows: the system exclusive message status byte (0xF0 or 0xF7), all 35 * message data bytes, and finally the end-of-exclusive flag (0xF7). 36 * The length reported by the <code>SysexMessage</code> object is therefore 37 * the length of the system exclusive data plus two: one byte for the status 38 * byte and one for the end-of-exclusive flag. 39 * <p> 40 * As dictated by the Standard MIDI Files specification, two status byte values are legal 41 * for a <code>SysexMessage</code> read from a MIDI file: 42 * <ul> 43 * <li>0xF0: System Exclusive message (same as in MIDI wire protocol)</li> 44 * <li>0xF7: Special System Exclusive message</li> 45 * </ul> 46 * <p> 47 * When Java Sound is used to handle system exclusive data that is being received 48 * using MIDI wire protocol, it should place the data in one or more 49 * <code>SysexMessages</code>. In this case, the length of the system exclusive data 50 * is not known in advance; the end of the system exclusive data is marked by an 51 * end-of-exclusive flag (0xF7) in the MIDI wire byte stream. 52 * <ul> 53 * <li>0xF0: System Exclusive message (same as in MIDI wire protocol)</li> 54 * <li>0xF7: End of Exclusive (EOX)</li> 55 * </ul> 56 * The first <code>SysexMessage</code> object containing data for a particular system 57 * exclusive message should have the status value 0xF0. If this message contains all 58 * the system exclusive data 59 * for the message, it should end with the status byte 0xF7 (EOX). 60 * Otherwise, additional system exclusive data should be sent in one or more 61 * <code>SysexMessages</code> with a status value of 0xF7. The <code>SysexMessage</code> 62 * containing the last of the data for the system exclusive message should end with the 63 * value 0xF7 (EOX) to mark the end of the system exclusive message. 64 * <p> 65 * If system exclusive data from <code>SysexMessages</code> objects is being transmitted 66 * using MIDI wire protocol, only the initial 0xF0 status byte, the system exclusive 67 * data itself, and the final 0xF7 (EOX) byte should be propagated; any 0xF7 status 68 * bytes used to indicate that a <code>SysexMessage</code> contains continuing system 69 * exclusive data should not be propagated via MIDI wire protocol. 70 * 71 * @author David Rivas 72 * @author Kara Kytle 73 * @author Florian Bomers 74 */ 75 public class SysexMessage extends MidiMessage { 76 77 78 // Status byte defines 79 80 81 /** 82 * Status byte for System Exclusive message (0xF0, or 240). 83 * @see MidiMessage#getStatus 84 */ 85 public static final int SYSTEM_EXCLUSIVE = 0xF0; // 240 86 87 88 /** 89 * Status byte for Special System Exclusive message (0xF7, or 247), which is used 90 * in MIDI files. It has the same value as END_OF_EXCLUSIVE, which 91 * is used in the real-time "MIDI wire" protocol. 92 * @see MidiMessage#getStatus 93 */ 94 public static final int SPECIAL_SYSTEM_EXCLUSIVE = 0xF7; // 247 95 96 97 // Instance variables 98 99 100 /* 101 * The data bytes for this system exclusive message. These are 102 * initialized to <code>null</code> and are set explicitly 103 * by {@link #setMessage(int, byte[], int, long) setMessage}. 104 */ 105 //protected byte[] data = null; 106 107 108 /** 109 * Constructs a new <code>SysexMessage</code>. The 110 * contents of the new message are guaranteed to specify 111 * a valid MIDI message. Subsequently, you may set the 112 * contents of the message using one of the <code>setMessage</code> 113 * methods. 114 * @see #setMessage 115 */ 116 public SysexMessage() { 117 this(new byte[2]); 118 // Default sysex message data: SOX followed by EOX 119 data[0] = (byte) (SYSTEM_EXCLUSIVE & 0xFF); 120 data[1] = (byte) (ShortMessage.END_OF_EXCLUSIVE & 0xFF); 121 } 122 123 /** 124 * Constructs a new {@code SysexMessage} and sets the data for 125 * the message. The first byte of the data array must be a valid system 126 * exclusive status byte (0xF0 or 0xF7). 127 * The contents of the message can be changed by using one of 128 * the {@code setMessage} methods. 129 * 130 * @param data the system exclusive message data including the status byte 131 * @param length the length of the valid message data in the array, 132 * including the status byte; it should be non-negative and less than 133 * or equal to {@code data.length} 134 * @throws InvalidMidiDataException if the parameter values 135 * do not specify a valid MIDI meta message. 136 * @see #setMessage(byte[], int) 137 * @see #setMessage(int, byte[], int) 138 * @see #getData() 139 * @since 1.7 140 */ 141 public SysexMessage(byte[] data, int length) 142 throws InvalidMidiDataException { 143 super(null); 144 setMessage(data, length); 145 } 146 147 /** 148 * Constructs a new {@code SysexMessage} and sets the data for the message. 149 * The contents of the message can be changed by using one of 150 * the {@code setMessage} methods. 151 * 152 * @param status the status byte for the message; it must be a valid system 153 * exclusive status byte (0xF0 or 0xF7) 154 * @param data the system exclusive message data (without the status byte) 155 * @param length the length of the valid message data in the array; 156 * it should be non-negative and less than or equal to 157 * {@code data.length} 158 * @throws InvalidMidiDataException if the parameter values 159 * do not specify a valid MIDI meta message. 160 * @see #setMessage(byte[], int) 161 * @see #setMessage(int, byte[], int) 162 * @see #getData() 163 * @since 1.7 164 */ 165 public SysexMessage(int status, byte[] data, int length) 166 throws InvalidMidiDataException { 167 super(null); 168 setMessage(status, data, length); 169 } 170 171 172 /** 173 * Constructs a new <code>SysexMessage</code>. 174 * @param data an array of bytes containing the complete message. 175 * The message data may be changed using the <code>setMessage</code> 176 * method. 177 * @see #setMessage 178 */ 179 protected SysexMessage(byte[] data) { 180 super(data); 181 } 182 183 184 /** 185 * Sets the data for the system exclusive message. The 186 * first byte of the data array must be a valid system 187 * exclusive status byte (0xF0 or 0xF7). 188 * @param data the system exclusive message data 189 * @param length the length of the valid message data in 190 * the array, including the status byte. 191 */ 192 public void setMessage(byte[] data, int length) throws InvalidMidiDataException { 193 int status = (data[0] & 0xFF); 194 if ((status != 0xF0) && (status != 0xF7)) { 195 throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status)); 196 } 197 super.setMessage(data, length); 198 } 199 200 201 /** 202 * Sets the data for the system exclusive message. 203 * @param status the status byte for the message (0xF0 or 0xF7) 204 * @param data the system exclusive message data 205 * @param length the length of the valid message data in 206 * the array 207 * @throws InvalidMidiDataException if the status byte is invalid for a sysex message 208 */ 209 public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException { 210 if ( (status != 0xF0) && (status != 0xF7) ) { 211 throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status)); 212 } 213 if (length < 0 || length > data.length) { 214 throw new IndexOutOfBoundsException("length out of bounds: "+length); 215 } 216 this.length = length + 1; 217 218 if (this.data==null || this.data.length < this.length) { 219 this.data = new byte[this.length]; 220 } 221 222 this.data[0] = (byte) (status & 0xFF); 223 if (length > 0) { 224 System.arraycopy(data, 0, this.data, 1, length); 225 } 226 } 227 228 229 /** 230 * Obtains a copy of the data for the system exclusive message. 231 * The returned array of bytes does not include the status byte. 232 * @return array containing the system exclusive message data. 233 */ 234 public byte[] getData() { 235 byte[] returnedArray = new byte[length - 1]; 236 System.arraycopy(data, 1, returnedArray, 0, (length - 1)); 237 return returnedArray; 238 } 239 240 241 /** 242 * Creates a new object of the same class and with the same contents 243 * as this object. 244 * @return a clone of this instance 245 */ 246 public Object clone() { 247 byte[] newData = new byte[length]; 248 System.arraycopy(data, 0, newData, 0, newData.length); 249 SysexMessage event = new SysexMessage(newData); 250 return event; 251 } 252 }