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