internal virtual void sysexBufferAppendBytes(int msg, int len) { for (int i = 0; i < len; i++) { byte b = (byte)msg; if ((msg & 0x80) != 0) { if (b == 0xF7) { // end of sysex sysexBufferAppendStatus(b); sysex(sysexBuffer, sysexBufferIndex); return; } // recursively handle embedded real-time messages CsPortMidiApi.PmEvent buffer = new CsPortMidiApi.PmEvent(); buffer.timestamp = timestamp; buffer.message = b; handleMidiIn(buffer); } else { sysexBuffer[sysexBufferIndex++] = b; } msg = msg >> 8; } }
protected internal bool trace = false; // used to print midi msgs for debugging public CsPortMidi() { if (pmRefCount == 0) { pm = new CsPortMidiApi(); pmRefCount++; checkError(CsPortMidiApi.Pm_Initialize()); } buffer = new CsPortMidiApi.PmEvent(); }
public virtual void handleMidiIn(CsPortMidiApi.PmEvent buffer) { if (trace) { Console.WriteLine("handleMidiIn: " + buffer.message.ToString("x")); } // rather than pass timestamps to every handler, where typically // timestamps are ignored, just save the timestamp as a member // variable where methods can access it if they want it timestamp = buffer.timestamp; int status = buffer.message & 0xFF; if (status < 0x80) { sysexBufferCheck(); // make enough space sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes return; } int command = status & 0xF0; int channel = status & 0x0F; int data1 = (buffer.message >> 8) & 0xFF; int data2 = (buffer.message >> 16) & 0xFF; switch (command) { case MIDI_NOTE_OFF: noteOff(channel, data1, data2); break; case MIDI_NOTE_ON: if (data2 > 0) { noteOn(channel, data1, data2); break; } else { noteOff(channel, data1); } break; case MIDI_CONTROL: control(channel, data1, data2); break; case MIDI_POLY_TOUCH: polyTouch(channel, data1, data2); break; case MIDI_TOUCH: touch(channel, data1); break; case MIDI_PITCH_BEND: pitchBend(channel, (data1 + (data2 << 7)) - 8192); break; case MIDI_PROGRAM: program(channel, data1); break; case 0xF0: switch (channel) { case 0: sysexBegin(buffer.message); break; case 1: mtcQuarterFrame(data1); goto case 2; case 2: songPosition(data1 + (data2 << 7)); break; case 3: songSelect(data1); break; case 4: // unused break; case 5: // unused break; case 6: tuneRequest(); break; case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break; case 8: clock(); break; case 9: tick(); break; case 0xA: clockStart(); break; case 0xB: clockContinue(); break; case 0xC: clockStop(); break; case 0xD: // unused break; case 0xE: activeSense(); break; case 0xF: reset(); break; } break; } }