diff options
Diffstat (limited to 'portmidi/pm_java/jportmidi/JPortMidi.java')
| -rw-r--r-- | portmidi/pm_java/jportmidi/JPortMidi.java | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/portmidi/pm_java/jportmidi/JPortMidi.java b/portmidi/pm_java/jportmidi/JPortMidi.java new file mode 100644 index 0000000..7116e19 --- /dev/null +++ b/portmidi/pm_java/jportmidi/JPortMidi.java | |||
| @@ -0,0 +1,541 @@ | |||
| 1 | package jportmidi; | ||
| 2 | |||
| 3 | /* PortMidi is a general class intended for any Java program using | ||
| 4 | the PortMidi library. It encapsulates JPortMidiApi with a more | ||
| 5 | object-oriented interface. A single PortMidi object can manage | ||
| 6 | up to one input stream and one output stream. | ||
| 7 | |||
| 8 | This class is not safely callable from multiple threads. It | ||
| 9 | is the client's responsibility to periodically call the Poll | ||
| 10 | method which checks for midi input and handles it. | ||
| 11 | */ | ||
| 12 | |||
| 13 | import jportmidi.*; | ||
| 14 | import jportmidi.JPortMidiApi.*; | ||
| 15 | |||
| 16 | public class JPortMidi { | ||
| 17 | |||
| 18 | // timecode to send message immediately | ||
| 19 | public final int NOW = 0; | ||
| 20 | |||
| 21 | // midi codes | ||
| 22 | public final int MIDI_NOTE_OFF = 0x80; | ||
| 23 | public final int MIDI_NOTE_ON = 0x90; | ||
| 24 | public final int CTRL_ALL_OFF = 123; | ||
| 25 | public final int MIDI_PITCH_BEND = 0xE0; | ||
| 26 | public final int MIDI_CLOCK = 0xF8; | ||
| 27 | public final int MIDI_CONTROL = 0xB0; | ||
| 28 | public final int MIDI_PROGRAM = 0xC0; | ||
| 29 | public final int MIDI_START = 0xFA; | ||
| 30 | public final int MIDI_STOP = 0xFC; | ||
| 31 | public final int MIDI_POLY_TOUCH = 0xA0; | ||
| 32 | public final int MIDI_TOUCH = 0xD0; | ||
| 33 | |||
| 34 | // error code -- cannot refresh device list while stream is open: | ||
| 35 | public final int pmStreamOpen = -5000; | ||
| 36 | public final int pmOutputNotOpen = -4999; | ||
| 37 | |||
| 38 | // access to JPortMidiApi is through a single, global instance | ||
| 39 | private static JPortMidiApi pm; | ||
| 40 | // a reference count tracks how many objects have it open | ||
| 41 | private static int pmRefCount = 0; | ||
| 42 | private static int openCount = 0; | ||
| 43 | |||
| 44 | public int error; // user can check here for error codes | ||
| 45 | private PortMidiStream input; | ||
| 46 | private PortMidiStream output; | ||
| 47 | private PmEvent buffer; | ||
| 48 | protected int timestamp; // remember timestamp from incoming messages | ||
| 49 | protected boolean trace = false; // used to print midi msgs for debugging | ||
| 50 | |||
| 51 | |||
| 52 | public JPortMidi() throws JPortMidiException { | ||
| 53 | if (pmRefCount == 0) { | ||
| 54 | pm = new JPortMidiApi(); | ||
| 55 | pmRefCount++; | ||
| 56 | System.out.println("Calling Pm_Initialize"); | ||
| 57 | checkError(pm.Pm_Initialize()); | ||
| 58 | System.out.println("Called Pm_Initialize"); | ||
| 59 | } | ||
| 60 | buffer = new PmEvent(); | ||
| 61 | } | ||
| 62 | |||
| 63 | public boolean getTrace() { return trace; } | ||
| 64 | |||
| 65 | // set the trace flag and return previous value | ||
| 66 | public boolean setTrace(boolean flag) { | ||
| 67 | boolean previous = trace; | ||
| 68 | trace = flag; | ||
| 69 | return previous; | ||
| 70 | } | ||
| 71 | |||
| 72 | // WARNING: you must not call this if any devices are open | ||
| 73 | public void refreshDeviceLists() | ||
| 74 | throws JPortMidiException | ||
| 75 | { | ||
| 76 | if (openCount > 0) { | ||
| 77 | throw new JPortMidiException(pmStreamOpen, | ||
| 78 | "RefreshDeviceLists called while stream is open"); | ||
| 79 | } | ||
| 80 | if (trace) System.out.println("Pm_Terminate"); | ||
| 81 | checkError(pm.Pm_Terminate()); | ||
| 82 | if (trace) System.out.println("Pm_Initialize"); | ||
| 83 | checkError(pm.Pm_Initialize()); | ||
| 84 | } | ||
| 85 | |||
| 86 | // there is no control over when/whether this is called, but it seems | ||
| 87 | // to be a good idea to close things when this object is collected | ||
| 88 | public void finalize() { | ||
| 89 | if (input != null) { | ||
| 90 | error = pm.Pm_Close(input); | ||
| 91 | } | ||
| 92 | if (input != null) { | ||
| 93 | int rslt = pm.Pm_Close(output); | ||
| 94 | // we may lose an error code from closing output, but don't | ||
| 95 | // lose any real error from closing input... | ||
| 96 | if (error == pm.pmNoError) error = rslt; | ||
| 97 | } | ||
| 98 | pmRefCount--; | ||
| 99 | if (pmRefCount == 0) { | ||
| 100 | error = pm.Pm_Terminate(); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | int checkError(int err) throws JPortMidiException | ||
| 105 | { | ||
| 106 | // note that Pm_Read and Pm_Write return positive result values | ||
| 107 | // which are not errors, so compare with >= | ||
| 108 | if (err >= pm.pmNoError) return err; | ||
| 109 | if (err == pm.pmHostError) { | ||
| 110 | throw new JPortMidiException(err, pm.Pm_GetHostErrorText()); | ||
| 111 | } else { | ||
| 112 | throw new JPortMidiException(err, pm.Pm_GetErrorText(err)); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | // ******** ACCESS TO TIME *********** | ||
| 117 | |||
| 118 | public void timeStart(int resolution) throws JPortMidiException { | ||
| 119 | checkError(pm.Pt_TimeStart(resolution)); | ||
| 120 | } | ||
| 121 | |||
| 122 | public void timeStop() throws JPortMidiException { | ||
| 123 | checkError(pm.Pt_TimeStop()); | ||
| 124 | } | ||
| 125 | |||
| 126 | public int timeGet() { | ||
| 127 | return pm.Pt_Time(); | ||
| 128 | } | ||
| 129 | |||
| 130 | public boolean timeStarted() { | ||
| 131 | return pm.Pt_TimeStarted(); | ||
| 132 | } | ||
| 133 | |||
| 134 | // ******* QUERY DEVICE INFORMATION ********* | ||
| 135 | |||
| 136 | public int countDevices() throws JPortMidiException { | ||
| 137 | return checkError(pm.Pm_CountDevices()); | ||
| 138 | } | ||
| 139 | |||
| 140 | public int getDefaultInputDeviceID() throws JPortMidiException { | ||
| 141 | return checkError(pm.Pm_GetDefaultInputDeviceID()); | ||
| 142 | } | ||
| 143 | |||
| 144 | public int getDefaultOutputDeviceID() throws JPortMidiException { | ||
| 145 | return checkError(pm.Pm_GetDefaultOutputDeviceID()); | ||
| 146 | } | ||
| 147 | |||
| 148 | public String getDeviceInterf(int i) { | ||
| 149 | return pm.Pm_GetDeviceInterf(i); | ||
| 150 | } | ||
| 151 | |||
| 152 | public String getDeviceName(int i) { | ||
| 153 | return pm.Pm_GetDeviceName(i); | ||
| 154 | } | ||
| 155 | |||
| 156 | public boolean getDeviceInput(int i) { | ||
| 157 | return pm.Pm_GetDeviceInput(i); | ||
| 158 | } | ||
| 159 | |||
| 160 | public boolean getDeviceOutput(int i) { | ||
| 161 | return pm.Pm_GetDeviceOutput(i); | ||
| 162 | } | ||
| 163 | |||
| 164 | // ********** MIDI INTERFACE ************ | ||
| 165 | |||
| 166 | public boolean isOpenInput() { | ||
| 167 | return input != null; | ||
| 168 | } | ||
| 169 | |||
| 170 | public void openInput(int inputDevice, int bufferSize) | ||
| 171 | throws JPortMidiException | ||
| 172 | { | ||
| 173 | openInput(inputDevice, "", bufferSize); | ||
| 174 | } | ||
| 175 | |||
| 176 | public void openInput(int inputDevice, String inputDriverInfo, int bufferSize) | ||
| 177 | throws JPortMidiException | ||
| 178 | { | ||
| 179 | if (isOpenInput()) pm.Pm_Close(input); | ||
| 180 | else input = new PortMidiStream(); | ||
| 181 | if (trace) { | ||
| 182 | System.out.println("openInput " + getDeviceName(inputDevice)); | ||
| 183 | } | ||
| 184 | checkError(pm.Pm_OpenInput(input, inputDevice, | ||
| 185 | inputDriverInfo, bufferSize)); | ||
| 186 | // if no exception, then increase count of open streams | ||
| 187 | openCount++; | ||
| 188 | } | ||
| 189 | |||
| 190 | public boolean isOpenOutput() { | ||
| 191 | return output != null; | ||
| 192 | } | ||
| 193 | |||
| 194 | public void openOutput(int outputDevice, int bufferSize, int latency) | ||
| 195 | throws JPortMidiException | ||
| 196 | { | ||
| 197 | openOutput(outputDevice, "", bufferSize, latency); | ||
| 198 | } | ||
| 199 | |||
| 200 | public void openOutput(int outputDevice, String outputDriverInfo, | ||
| 201 | int bufferSize, int latency) throws JPortMidiException { | ||
| 202 | if (isOpenOutput()) pm.Pm_Close(output); | ||
| 203 | else output = new PortMidiStream(); | ||
| 204 | if (trace) { | ||
| 205 | System.out.println("openOutput " + getDeviceName(outputDevice)); | ||
| 206 | } | ||
| 207 | checkError(pm.Pm_OpenOutput(output, outputDevice, outputDriverInfo, | ||
| 208 | bufferSize, latency)); | ||
| 209 | // if no exception, then increase count of open streams | ||
| 210 | openCount++; | ||
| 211 | } | ||
| 212 | |||
| 213 | public void setFilter(int filters) throws JPortMidiException { | ||
| 214 | if (input == null) return; // no effect if input not open | ||
| 215 | checkError(pm.Pm_SetFilter(input, filters)); | ||
| 216 | } | ||
| 217 | |||
| 218 | public void setChannelMask(int mask) throws JPortMidiException { | ||
| 219 | if (input == null) return; // no effect if input not open | ||
| 220 | checkError(pm.Pm_SetChannelMask(input, mask)); | ||
| 221 | } | ||
| 222 | |||
| 223 | public void abort() throws JPortMidiException { | ||
| 224 | if (output == null) return; // no effect if output not open | ||
| 225 | checkError(pm.Pm_Abort(output)); | ||
| 226 | } | ||
| 227 | |||
| 228 | // In keeping with the idea that this class represents an input and output, | ||
| 229 | // there are separate Close methods for input and output streams, avoiding | ||
| 230 | // the need for clients to ever deal directly with a stream object | ||
| 231 | public void closeInput() throws JPortMidiException { | ||
| 232 | if (input == null) return; // no effect if input not open | ||
| 233 | checkError(pm.Pm_Close(input)); | ||
| 234 | input = null; | ||
| 235 | openCount--; | ||
| 236 | } | ||
| 237 | |||
| 238 | public void closeOutput() throws JPortMidiException { | ||
| 239 | if (output == null) return; // no effect if output not open | ||
| 240 | checkError(pm.Pm_Close(output)); | ||
| 241 | output = null; | ||
| 242 | openCount--; | ||
| 243 | } | ||
| 244 | |||
| 245 | // Poll should be called by client to process input messages (if any) | ||
| 246 | public void poll() throws JPortMidiException { | ||
| 247 | if (input == null) return; // does nothing until input is opened | ||
| 248 | while (true) { | ||
| 249 | int rslt = pm.Pm_Read(input, buffer); | ||
| 250 | checkError(rslt); | ||
| 251 | if (rslt == 0) return; // no more messages | ||
| 252 | handleMidiIn(buffer); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | public void writeShort(int when, int msg) throws JPortMidiException { | ||
| 257 | if (output == null) | ||
| 258 | throw new JPortMidiException(pmOutputNotOpen, | ||
| 259 | "Output stream not open"); | ||
| 260 | if (trace) { | ||
| 261 | System.out.println("writeShort: " + Integer.toHexString(msg)); | ||
| 262 | } | ||
| 263 | checkError(pm.Pm_WriteShort(output, when, msg)); | ||
| 264 | } | ||
| 265 | |||
| 266 | public void writeSysEx(int when, byte msg[]) throws JPortMidiException { | ||
| 267 | if (output == null) | ||
| 268 | throw new JPortMidiException(pmOutputNotOpen, | ||
| 269 | "Output stream not open"); | ||
| 270 | if (trace) { | ||
| 271 | System.out.print("writeSysEx: "); | ||
| 272 | for (int i = 0; i < msg.length; i++) { | ||
| 273 | System.out.print(Integer.toHexString(msg[i])); | ||
| 274 | } | ||
| 275 | System.out.print("\n"); | ||
| 276 | } | ||
| 277 | checkError(pm.Pm_WriteSysEx(output, when, msg)); | ||
| 278 | } | ||
| 279 | |||
| 280 | public int midiChanMessage(int chan, int status, int data1, int data2) { | ||
| 281 | return (((data2 << 16) & 0xFF0000) | | ||
| 282 | ((data1 << 8) & 0xFF00) | | ||
| 283 | (status & 0xF0) | | ||
| 284 | (chan & 0xF)); | ||
| 285 | } | ||
| 286 | |||
| 287 | public int midiMessage(int status, int data1, int data2) { | ||
| 288 | return ((((data2) << 16) & 0xFF0000) | | ||
| 289 | (((data1) << 8) & 0xFF00) | | ||
| 290 | ((status) & 0xFF)); | ||
| 291 | } | ||
| 292 | |||
| 293 | public void midiAllOff(int channel) throws JPortMidiException { | ||
| 294 | midiAllOff(channel, NOW); | ||
| 295 | } | ||
| 296 | |||
| 297 | public void midiAllOff(int chan, int when) throws JPortMidiException { | ||
| 298 | writeShort(when, midiChanMessage(chan, MIDI_CONTROL, CTRL_ALL_OFF, 0)); | ||
| 299 | } | ||
| 300 | |||
| 301 | public void midiPitchBend(int chan, int value) throws JPortMidiException { | ||
| 302 | midiPitchBend(chan, value, NOW); | ||
| 303 | } | ||
| 304 | |||
| 305 | public void midiPitchBend(int chan, int value, int when) | ||
| 306 | throws JPortMidiException { | ||
| 307 | writeShort(when, | ||
| 308 | midiChanMessage(chan, MIDI_PITCH_BEND, value, value >> 7)); | ||
| 309 | } | ||
| 310 | |||
| 311 | public void midiClock() throws JPortMidiException { | ||
| 312 | midiClock(NOW); | ||
| 313 | } | ||
| 314 | |||
| 315 | public void midiClock(int when) throws JPortMidiException { | ||
| 316 | writeShort(when, midiMessage(MIDI_CLOCK, 0, 0)); | ||
| 317 | } | ||
| 318 | |||
| 319 | public void midiControl(int chan, int control, int value) | ||
| 320 | throws JPortMidiException { | ||
| 321 | midiControl(chan, control, value, NOW); | ||
| 322 | } | ||
| 323 | |||
| 324 | public void midiControl(int chan, int control, int value, int when) | ||
| 325 | throws JPortMidiException { | ||
| 326 | writeShort(when, midiChanMessage(chan, MIDI_CONTROL, control, value)); | ||
| 327 | } | ||
| 328 | |||
| 329 | public void midiNote(int chan, int pitch, int vel) | ||
| 330 | throws JPortMidiException { | ||
| 331 | midiNote(chan, pitch, vel, NOW); | ||
| 332 | } | ||
| 333 | |||
| 334 | public void midiNote(int chan, int pitch, int vel, int when) | ||
| 335 | throws JPortMidiException { | ||
| 336 | writeShort(when, midiChanMessage(chan, MIDI_NOTE_ON, pitch, vel)); | ||
| 337 | } | ||
| 338 | |||
| 339 | public void midiProgram(int chan, int program) | ||
| 340 | throws JPortMidiException { | ||
| 341 | midiProgram(chan, program, NOW); | ||
| 342 | } | ||
| 343 | |||
| 344 | public void midiProgram(int chan, int program, int when) | ||
| 345 | throws JPortMidiException { | ||
| 346 | writeShort(when, midiChanMessage(chan, MIDI_PROGRAM, program, 0)); | ||
| 347 | } | ||
| 348 | |||
| 349 | public void midiStart() | ||
| 350 | throws JPortMidiException { | ||
| 351 | midiStart(NOW); | ||
| 352 | } | ||
| 353 | |||
| 354 | public void midiStart(int when) | ||
| 355 | throws JPortMidiException { | ||
| 356 | writeShort(when, midiMessage(MIDI_START, 0, 0)); | ||
| 357 | } | ||
| 358 | |||
| 359 | public void midiStop() | ||
| 360 | throws JPortMidiException { | ||
| 361 | midiStop(NOW); | ||
| 362 | } | ||
| 363 | |||
| 364 | public void midiStop(int when) | ||
| 365 | throws JPortMidiException { | ||
| 366 | writeShort(when, midiMessage(MIDI_STOP, 0, 0)); | ||
| 367 | } | ||
| 368 | |||
| 369 | public void midiPolyTouch(int chan, int key, int value) | ||
| 370 | throws JPortMidiException { | ||
| 371 | midiPolyTouch(chan, key, value, NOW); | ||
| 372 | } | ||
| 373 | |||
| 374 | public void midiPolyTouch(int chan, int key, int value, int when) | ||
| 375 | throws JPortMidiException { | ||
| 376 | writeShort(when, midiChanMessage(chan, MIDI_POLY_TOUCH, key, value)); | ||
| 377 | } | ||
| 378 | |||
| 379 | public void midiTouch(int chan, int value) | ||
| 380 | throws JPortMidiException { | ||
| 381 | midiTouch(chan, value, NOW); | ||
| 382 | } | ||
| 383 | |||
| 384 | public void midiTouch(int chan, int value, int when) | ||
| 385 | throws JPortMidiException { | ||
| 386 | writeShort(when, midiChanMessage(chan, MIDI_TOUCH, value, 0)); | ||
| 387 | } | ||
| 388 | |||
| 389 | // ****** now we implement the message handlers ****** | ||
| 390 | |||
| 391 | // an array for incoming sysex messages that can grow. | ||
| 392 | // The downside is that after getting a message, we | ||
| 393 | |||
| 394 | private byte sysexBuffer[] = null; | ||
| 395 | private int sysexBufferIndex = 0; | ||
| 396 | |||
| 397 | void sysexBufferReset() { | ||
| 398 | sysexBufferIndex = 0; | ||
| 399 | if (sysexBuffer == null) sysexBuffer = new byte[256]; | ||
| 400 | } | ||
| 401 | |||
| 402 | void sysexBufferCheck() { | ||
| 403 | if (sysexBuffer.length < sysexBufferIndex + 4) { | ||
| 404 | byte bigger[] = new byte[sysexBuffer.length * 2]; | ||
| 405 | for (int i = 0; i < sysexBufferIndex; i++) { | ||
| 406 | bigger[i] = sysexBuffer[i]; | ||
| 407 | } | ||
| 408 | sysexBuffer = bigger; | ||
| 409 | } | ||
| 410 | // now we have space to write some bytes | ||
| 411 | } | ||
| 412 | |||
| 413 | // call this to insert Sysex and EOX status bytes | ||
| 414 | // call sysexBufferAppendBytes to insert anything else | ||
| 415 | void sysexBufferAppendStatus(byte status) { | ||
| 416 | sysexBuffer[sysexBufferIndex++] = status; | ||
| 417 | } | ||
| 418 | |||
| 419 | void sysexBufferAppendBytes(int msg, int len) { | ||
| 420 | for (int i = 0; i < len; i++) { | ||
| 421 | byte b = (byte) msg; | ||
| 422 | if ((msg & 0x80) != 0) { | ||
| 423 | if (b == 0xF7) { // end of sysex | ||
| 424 | sysexBufferAppendStatus(b); | ||
| 425 | sysex(sysexBuffer, sysexBufferIndex); | ||
| 426 | return; | ||
| 427 | } | ||
| 428 | // recursively handle embedded real-time messages | ||
| 429 | PmEvent buffer = new PmEvent(); | ||
| 430 | buffer.timestamp = timestamp; | ||
| 431 | buffer.message = b; | ||
| 432 | handleMidiIn(buffer); | ||
| 433 | } else { | ||
| 434 | sysexBuffer[sysexBufferIndex++] = b; | ||
| 435 | } | ||
| 436 | msg = msg >> 8; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | void sysexBegin(int msg) { | ||
| 441 | sysexBufferReset(); // start from 0, we have at least 256 bytes now | ||
| 442 | sysexBufferAppendStatus((byte) (msg & 0xFF)); // first byte is special | ||
| 443 | sysexBufferAppendBytes(msg >> 8, 3); // process remaining bytes | ||
| 444 | } | ||
| 445 | |||
| 446 | public void handleMidiIn(PmEvent buffer) | ||
| 447 | { | ||
| 448 | if (trace) { | ||
| 449 | System.out.println("handleMidiIn: " + | ||
| 450 | Integer.toHexString(buffer.message)); | ||
| 451 | } | ||
| 452 | // rather than pass timestamps to every handler, where typically | ||
| 453 | // timestamps are ignored, just save the timestamp as a member | ||
| 454 | // variable where methods can access it if they want it | ||
| 455 | timestamp = buffer.timestamp; | ||
| 456 | int status = buffer.message & 0xFF; | ||
| 457 | if (status < 0x80) { | ||
| 458 | sysexBufferCheck(); // make enough space | ||
| 459 | sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes | ||
| 460 | return; | ||
| 461 | } | ||
| 462 | int command = status & 0xF0; | ||
| 463 | int channel = status & 0x0F; | ||
| 464 | int data1 = (buffer.message >> 8) & 0xFF; | ||
| 465 | int data2 = (buffer.message >> 16) & 0xFF; | ||
| 466 | switch (command) { | ||
| 467 | case MIDI_NOTE_OFF: | ||
| 468 | noteOff(channel, data1, data2); break; | ||
| 469 | case MIDI_NOTE_ON: | ||
| 470 | if (data2 > 0) { | ||
| 471 | noteOn(channel, data1, data2); break; | ||
| 472 | } else { | ||
| 473 | noteOff(channel, data1); | ||
| 474 | } | ||
| 475 | break; | ||
| 476 | case MIDI_CONTROL: | ||
| 477 | control(channel, data1, data2); break; | ||
| 478 | case MIDI_POLY_TOUCH: | ||
| 479 | polyTouch(channel, data1, data2); break; | ||
| 480 | case MIDI_TOUCH: | ||
| 481 | touch(channel, data1); break; | ||
| 482 | case MIDI_PITCH_BEND: | ||
| 483 | pitchBend(channel, (data1 + (data2 << 7)) - 8192); break; | ||
| 484 | case MIDI_PROGRAM: | ||
| 485 | program(channel, data1); break; | ||
| 486 | case 0xF0: | ||
| 487 | switch (channel) { | ||
| 488 | case 0: sysexBegin(buffer.message); break; | ||
| 489 | case 1: mtcQuarterFrame(data1); | ||
| 490 | case 2: songPosition(data1 + (data2 << 7)); break; | ||
| 491 | case 3: songSelect(data1); break; | ||
| 492 | case 4: /* unused */ break; | ||
| 493 | case 5: /* unused */ break; | ||
| 494 | case 6: tuneRequest(); break; | ||
| 495 | case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break; | ||
| 496 | case 8: clock(); break; | ||
| 497 | case 9: tick(); break; | ||
| 498 | case 0xA: clockStart(); break; | ||
| 499 | case 0xB: clockContinue(); break; | ||
| 500 | case 0xC: clockStop(); break; | ||
| 501 | case 0xD: /* unused */ break; | ||
| 502 | case 0xE: activeSense(); break; | ||
| 503 | case 0xF: reset(); break; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | // the value ranges from +8181 to -8192. The interpretation is | ||
| 509 | // synthesizer dependent. Often the range is +/- one whole step | ||
| 510 | // (two semitones), but the range is usually adjustable within | ||
| 511 | // the synthesizer. | ||
| 512 | void pitchBend(int channel, int value) { return; } | ||
| 513 | void control(int channel, int control, int value) { return; } | ||
| 514 | void noteOn(int channel, int pitch, int velocity) { return; } | ||
| 515 | // you can handle velocity in note-off if you want, but the default | ||
| 516 | // is to drop the velocity and call the simpler NoteOff handler | ||
| 517 | void noteOff(int channel, int pitch, int velocity) { | ||
| 518 | noteOff(channel, pitch); | ||
| 519 | } | ||
| 520 | // if the subclass wants to implement NoteOff with velocity, it | ||
| 521 | // should override the following to make sure all NoteOffs are handled | ||
| 522 | void noteOff(int channel, int pitch) { return; } | ||
| 523 | void program(int channel, int program) { return; } | ||
| 524 | // the byte array may be bigger than the message, length tells how | ||
| 525 | // many bytes in the array are part of the message | ||
| 526 | void sysex(byte[] msg, int length) { return; } | ||
| 527 | void polyTouch(int channel, int key, int value) { return; } | ||
| 528 | void touch(int channel, int value) { return; } | ||
| 529 | void mtcQuarterFrame(int value) { return; } | ||
| 530 | // the value is a 14-bit integer representing 16th notes | ||
| 531 | void songPosition(int value) { return; } | ||
| 532 | void songSelect(int value) { return; } | ||
| 533 | void tuneRequest() { return; } | ||
| 534 | void clock() { return; } // represents 1/24th of a quarter note | ||
| 535 | void tick() { return; } // represents 10ms | ||
| 536 | void clockStart() { return; } | ||
| 537 | void clockStop() { return; } | ||
| 538 | void clockContinue() { return; } | ||
| 539 | void activeSense() { return; } | ||
| 540 | void reset() { return; } | ||
| 541 | } | ||
