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 ShortMessage} contains a MIDI message that has at most two data 30 * bytes following its status byte. The types of MIDI message that satisfy this 31 * criterion are channel voice, channel mode, system common, and system 32 * real-time--in other words, everything except system exclusive and 33 * meta-events. The {@code ShortMessage} class provides methods for getting and 34 * setting the contents of the MIDI message. 35 * <p> 36 * A number of {@code ShortMessage} methods have integer parameters by which you 37 * specify a MIDI status or data byte. If you know the numeric value, you can 38 * express it directly. For system common and system real-time messages, you can 39 * often use the corresponding fields of {@code ShortMessage}, such as 40 * {@link #SYSTEM_RESET SYSTEM_RESET}. For channel messages, the upper four bits 41 * of the status byte are specified by a command value and the lower four bits 42 * are specified by a MIDI channel number. To convert incoming MIDI data bytes 43 * that are in the form of Java's signed bytes, you can use the 44 * <a href="MidiMessage.html#integersVsBytes">conversion code</a> given in the 45 * {@link MidiMessage} class description. 46 * 47 * @author David Rivas 48 * @author Kara Kytle 49 * @author Florian Bomers 50 * @see SysexMessage 51 * @see MetaMessage 52 */ 53 public class ShortMessage extends MidiMessage { 54 55 // Status byte defines 56 57 // System common messages 58 59 /** 60 * Status byte for MIDI Time Code Quarter Frame message (0xF1, or 241). 61 * 62 * @see MidiMessage#getStatus 63 */ 64 public static final int MIDI_TIME_CODE = 0xF1; // 241 65 66 /** 67 * Status byte for Song Position Pointer message (0xF2, or 242). 68 * 69 * @see MidiMessage#getStatus 70 */ 71 public static final int SONG_POSITION_POINTER = 0xF2; // 242 72 73 /** 74 * Status byte for MIDI Song Select message (0xF3, or 243). 75 * 76 * @see MidiMessage#getStatus 77 */ 78 public static final int SONG_SELECT = 0xF3; // 243 79 80 /** 81 * Status byte for Tune Request message (0xF6, or 246). 82 * 83 * @see MidiMessage#getStatus 84 */ 85 public static final int TUNE_REQUEST = 0xF6; // 246 86 87 /** 88 * Status byte for End of System Exclusive message (0xF7, or 247). 89 * 90 * @see MidiMessage#getStatus 91 */ 92 public static final int END_OF_EXCLUSIVE = 0xF7; // 247 93 94 // System real-time messages 95 96 /** 97 * Status byte for Timing Clock message (0xF8, or 248). 98 * 99 * @see MidiMessage#getStatus 100 */ 101 public static final int TIMING_CLOCK = 0xF8; // 248 102 103 /** 104 * Status byte for Start message (0xFA, or 250). 105 * 106 * @see MidiMessage#getStatus 107 */ 108 public static final int START = 0xFA; // 250 109 110 /** 111 * Status byte for Continue message (0xFB, or 251). 112 * 113 * @see MidiMessage#getStatus 114 */ 115 public static final int CONTINUE = 0xFB; // 251 116 117 /** 118 * Status byte for Stop message (0xFC, or 252). 119 * 120 * @see MidiMessage#getStatus 121 */ 122 public static final int STOP = 0xFC; //252 123 124 /** 125 * Status byte for Active Sensing message (0xFE, or 254). 126 * 127 * @see MidiMessage#getStatus 128 */ 129 public static final int ACTIVE_SENSING = 0xFE; // 254 130 131 /** 132 * Status byte for System Reset message (0xFF, or 255). 133 * 134 * @see MidiMessage#getStatus 135 */ 136 public static final int SYSTEM_RESET = 0xFF; // 255 137 138 // Channel voice message upper nibble defines 139 140 /** 141 * Command value for Note Off message (0x80, or 128). 142 */ 143 public static final int NOTE_OFF = 0x80; // 128 144 145 /** 146 * Command value for Note On message (0x90, or 144). 147 */ 148 public static final int NOTE_ON = 0x90; // 144 149 150 /** 151 * Command value for Polyphonic Key Pressure (Aftertouch) message (0xA0, or 152 * 160). 153 */ 154 public static final int POLY_PRESSURE = 0xA0; // 160 155 156 /** 157 * Command value for Control Change message (0xB0, or 176). 158 */ 159 public static final int CONTROL_CHANGE = 0xB0; // 176 160 161 /** 162 * Command value for Program Change message (0xC0, or 192). 163 */ 164 public static final int PROGRAM_CHANGE = 0xC0; // 192 165 166 /** 167 * Command value for Channel Pressure (Aftertouch) message (0xD0, or 208). 168 */ 169 public static final int CHANNEL_PRESSURE = 0xD0; // 208 170 171 /** 172 * Command value for Pitch Bend message (0xE0, or 224). 173 */ 174 public static final int PITCH_BEND = 0xE0; // 224 175 176 /** 177 * Constructs a new {@code ShortMessage}. The contents of the new message 178 * are guaranteed to specify a valid MIDI message. Subsequently, you may set 179 * the contents of the message using one of the {@code setMessage} methods. 180 * 181 * @see #setMessage 182 */ 183 public ShortMessage() { 184 this(new byte[3]); 185 // Default message data: NOTE_ON on Channel 0 with max volume 186 data[0] = (byte) (NOTE_ON & 0xFF); 187 data[1] = (byte) 64; 188 data[2] = (byte) 127; 189 length = 3; 190 } 191 192 /** 193 * Constructs a new {@code ShortMessage} which represents a MIDI message 194 * that takes no data bytes. The contents of the message can be changed by 195 * using one of the {@code setMessage} methods. 196 * 197 * @param status the MIDI status byte 198 * @throws InvalidMidiDataException if {@code status} does not specify a 199 * valid MIDI status byte for a message that requires no data bytes 200 * @see #setMessage(int) 201 * @see #setMessage(int, int, int) 202 * @see #setMessage(int, int, int, int) 203 * @see #getStatus() 204 * @since 1.7 205 */ 206 public ShortMessage(int status) throws InvalidMidiDataException { 207 super(null); 208 setMessage(status); // can throw InvalidMidiDataException 209 } 210 211 /** 212 * Constructs a new {@code ShortMessage} which represents a MIDI message 213 * that takes up to two data bytes. If the message only takes one data byte, 214 * the second data byte is ignored. If the message does not take any data 215 * bytes, both data bytes are ignored. The contents of the message can be 216 * changed by using one of the {@code setMessage} methods. 217 * 218 * @param status the MIDI status byte 219 * @param data1 the first data byte 220 * @param data2 the second data byte 221 * @throws InvalidMidiDataException if the status byte or all data bytes 222 * belonging to the message do not specify a valid MIDI message 223 * @see #setMessage(int) 224 * @see #setMessage(int, int, int) 225 * @see #setMessage(int, int, int, int) 226 * @see #getStatus() 227 * @see #getData1() 228 * @see #getData2() 229 * @since 1.7 230 */ 231 public ShortMessage(int status, int data1, int data2) 232 throws InvalidMidiDataException { 233 super(null); 234 setMessage(status, data1, data2); // can throw InvalidMidiDataException 235 } 236 237 /** 238 * Constructs a new {@code ShortMessage} which represents a channel MIDI 239 * message that takes up to two data bytes. If the message only takes one 240 * data byte, the second data byte is ignored. If the message does not take 241 * any data bytes, both data bytes are ignored. The contents of the message 242 * can be changed by using one of the {@code setMessage} methods. 243 * 244 * @param command the MIDI command represented by this message 245 * @param channel the channel associated with the message 246 * @param data1 the first data byte 247 * @param data2 the second data byte 248 * @throws InvalidMidiDataException if the command value, channel value or 249 * all data bytes belonging to the message do not specify a valid 250 * MIDI message 251 * @see #setMessage(int) 252 * @see #setMessage(int, int, int) 253 * @see #setMessage(int, int, int, int) 254 * @see #getCommand() 255 * @see #getChannel() 256 * @see #getData1() 257 * @see #getData2() 258 * @since 1.7 259 */ 260 public ShortMessage(int command, int channel, int data1, int data2) 261 throws InvalidMidiDataException { 262 super(null); 263 setMessage(command, channel, data1, data2); 264 } 265 266 /** 267 * Constructs a new {@code ShortMessage}. 268 * 269 * @param data an array of bytes containing the complete message. The 270 * message data may be changed using the {@code setMessage} method. 271 * @see #setMessage 272 */ 273 // $$fb this should throw an Exception in case of an illegal message! 274 protected ShortMessage(byte[] data) { 275 // $$fb this may set an invalid message. 276 // Can't correct without compromising compatibility 277 super(data); 278 } 279 280 /** 281 * Sets the parameters for a MIDI message that takes no data bytes. 282 * 283 * @param status the MIDI status byte 284 * @throws InvalidMidiDataException if {@code status} does not specify a 285 * valid MIDI status byte for a message that requires no data bytes 286 * @see #setMessage(int, int, int) 287 * @see #setMessage(int, int, int, int) 288 */ 289 public void setMessage(int status) throws InvalidMidiDataException { 290 // check for valid values 291 int dataLength = getDataLength(status); // can throw InvalidMidiDataException 292 if (dataLength != 0) { 293 throw new InvalidMidiDataException("Status byte; " + status + " requires " + dataLength + " data bytes"); 294 } 295 setMessage(status, 0, 0); 296 } 297 298 /** 299 * Sets the parameters for a MIDI message that takes one or two data bytes. 300 * If the message takes only one data byte, the second data byte is ignored; 301 * if the message does not take any data bytes, both data bytes are ignored. 302 * 303 * @param status the MIDI status byte 304 * @param data1 the first data byte 305 * @param data2 the second data byte 306 * @throws InvalidMidiDataException if the status byte, or all data bytes 307 * belonging to the message, do not specify a valid MIDI message 308 * @see #setMessage(int, int, int, int) 309 * @see #setMessage(int) 310 */ 311 public void setMessage(int status, int data1, int data2) throws InvalidMidiDataException { 312 // check for valid values 313 int dataLength = getDataLength(status); // can throw InvalidMidiDataException 314 if (dataLength > 0) { 315 if (data1 < 0 || data1 > 127) { 316 throw new InvalidMidiDataException("data1 out of range: " + data1); 317 } 318 if (dataLength > 1) { 319 if (data2 < 0 || data2 > 127) { 320 throw new InvalidMidiDataException("data2 out of range: " + data2); 321 } 322 } 323 } 324 325 326 // set the length 327 length = dataLength + 1; 328 // re-allocate array if ShortMessage(byte[]) constructor gave array with fewer elements 329 if (data == null || data.length < length) { 330 data = new byte[3]; 331 } 332 333 // set the data 334 data[0] = (byte) (status & 0xFF); 335 if (length > 1) { 336 data[1] = (byte) (data1 & 0xFF); 337 if (length > 2) { 338 data[2] = (byte) (data2 & 0xFF); 339 } 340 } 341 } 342 343 /** 344 * Sets the short message parameters for a channel message which takes up to 345 * two data bytes. If the message only takes one data byte, the second data 346 * byte is ignored; if the message does not take any data bytes, both data 347 * bytes are ignored. 348 * 349 * @param command the MIDI command represented by this message 350 * @param channel the channel associated with the message 351 * @param data1 the first data byte 352 * @param data2 the second data byte 353 * @throws InvalidMidiDataException if the status byte or all data bytes 354 * belonging to the message, do not specify a valid MIDI message 355 * @see #setMessage(int, int, int) 356 * @see #setMessage(int) 357 * @see #getCommand 358 * @see #getChannel 359 * @see #getData1 360 * @see #getData2 361 */ 362 public void setMessage(int command, int channel, int data1, int data2) throws InvalidMidiDataException { 363 // check for valid values 364 if (command >= 0xF0 || command < 0x80) { 365 throw new InvalidMidiDataException("command out of range: 0x" + Integer.toHexString(command)); 366 } 367 if ((channel & 0xFFFFFFF0) != 0) { // <=> (channel<0 || channel>15) 368 throw new InvalidMidiDataException("channel out of range: " + channel); 369 } 370 setMessage((command & 0xF0) | (channel & 0x0F), data1, data2); 371 } 372 373 /** 374 * Obtains the MIDI channel associated with this event. This method assumes 375 * that the event is a MIDI channel message; if not, the return value will 376 * not be meaningful. 377 * 378 * @return MIDI channel associated with the message 379 * @see #setMessage(int, int, int, int) 380 */ 381 public int getChannel() { 382 // this returns 0 if an invalid message is set 383 return (getStatus() & 0x0F); 384 } 385 386 /** 387 * Obtains the MIDI command associated with this event. This method assumes 388 * that the event is a MIDI channel message; if not, the return value will 389 * not be meaningful. 390 * 391 * @return the MIDI command associated with this event 392 * @see #setMessage(int, int, int, int) 393 */ 394 public int getCommand() { 395 // this returns 0 if an invalid message is set 396 return (getStatus() & 0xF0); 397 } 398 399 /** 400 * Obtains the first data byte in the message. 401 * 402 * @return the value of the {@code data1} field 403 * @see #setMessage(int, int, int) 404 */ 405 public int getData1() { 406 if (length > 1) { 407 return (data[1] & 0xFF); 408 } 409 return 0; 410 } 411 412 /** 413 * Obtains the second data byte in the message. 414 * 415 * @return the value of the {@code data2} field 416 * @see #setMessage(int, int, int) 417 */ 418 public int getData2() { 419 if (length > 2) { 420 return (data[2] & 0xFF); 421 } 422 return 0; 423 } 424 425 /** 426 * Creates a new object of the same class and with the same contents as this 427 * object. 428 * 429 * @return a clone of this instance 430 */ 431 @Override 432 public Object clone() { 433 byte[] newData = new byte[length]; 434 System.arraycopy(data, 0, newData, 0, newData.length); 435 436 ShortMessage msg = new ShortMessage(newData); 437 return msg; 438 } 439 440 /** 441 * Retrieves the number of data bytes associated with a particular status 442 * byte value. 443 * 444 * @param status status byte value, which must represent a short MIDI 445 * message 446 * @return data length in bytes (0, 1, or 2) 447 * @throws InvalidMidiDataException if the {@code status} argument does not 448 * represent the status byte for any short message 449 */ 450 protected final int getDataLength(int status) throws InvalidMidiDataException { 451 // system common and system real-time messages 452 switch(status) { 453 case 0xF6: // Tune Request 454 case 0xF7: // EOX 455 // System real-time messages 456 case 0xF8: // Timing Clock 457 case 0xF9: // Undefined 458 case 0xFA: // Start 459 case 0xFB: // Continue 460 case 0xFC: // Stop 461 case 0xFD: // Undefined 462 case 0xFE: // Active Sensing 463 case 0xFF: // System Reset 464 return 0; 465 case 0xF1: // MTC Quarter Frame 466 case 0xF3: // Song Select 467 return 1; 468 case 0xF2: // Song Position Pointer 469 return 2; 470 default: 471 } 472 473 // channel voice and mode messages 474 switch(status & 0xF0) { 475 case 0x80: 476 case 0x90: 477 case 0xA0: 478 case 0xB0: 479 case 0xE0: 480 return 2; 481 case 0xC0: 482 case 0xD0: 483 return 1; 484 default: 485 throw new InvalidMidiDataException("Invalid status byte: " + status); 486 } 487 } 488 }