void SprayEvent(MIDIEvent *ev, uint32 time) { switch (ev->status & 0xF0) { case B_NOTE_OFF: SprayNoteOff((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time); break; case B_NOTE_ON: SprayNoteOn((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time); break; case B_KEY_PRESSURE: SprayKeyPressure((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time); break; case B_CONTROL_CHANGE: SprayControlChange((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time); break; case B_PROGRAM_CHANGE: SprayProgramChange((ev->status & 0x0F) + 1, ev->data[0], time); break; case B_CHANNEL_PRESSURE: SprayChannelPressure((ev->status & 0x0F) + 1, ev->data[0], time); break; case B_PITCH_BEND: SprayPitchBend((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time); break; case 0xF: switch (ev->status) { case B_SYS_EX_START: SpraySystemExclusive(ev->extraData, ev->extraLen, time); break; case B_MIDI_TIME_CODE: case B_SONG_POSITION: case B_SONG_SELECT: case B_CABLE_MESSAGE: case B_TUNE_REQUEST: case B_SYS_EX_END: SpraySystemCommon(ev->status, ev->data[0], ev->data[1], time); break; case B_TIMING_CLOCK: case B_START: case B_STOP: case B_CONTINUE: case B_ACTIVE_SENSING: SpraySystemRealTime(ev->status, time); break; case B_SYSTEM_RESET: if (ev->data[0] == 0x51 && ev->data[1] == 0x03) { assert(ev->extraLen == 3); int val = (ev->extraData[0] << 16) | (ev->extraData[1] << 8) | ev->extraData[2]; int tempo = 60000000 / val; SprayTempoChange(tempo, time); } else { SpraySystemRealTime(ev->status, time); } } break; } }
int32 MidiPortProducer::GetData() { uint8 msgBuf[3]; uint8* sysexBuf = NULL; uint8* msgPtr = NULL; size_t msgSize = 0; size_t needed = 0; uint8 runningStatus = 0; bool haveSysEx = false; size_t sysexAlloc = 0; size_t sysexSize = 0; uint8 next = 0; while (fKeepRunning) { if (read(fFileDescriptor, &next, 1) != 1) { if (errno == B_CANCELED) fKeepRunning = false; else perror("Error reading data from driver"); break; } bigtime_t timestamp = system_time(); if (haveSysEx) { // System Exclusive mode if (next < 0x80) { // System Exclusive data byte sysexBuf[sysexSize++] = next; if (sysexSize == sysexAlloc) { sysexAlloc *= 2; sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc); } continue; } else if ((next & 0xF8) == 0xF8) { // System Realtime interleaved in System Exclusive sequence SpraySystemRealTime(next, timestamp); continue; } else { // Whatever byte, this one ends the running SysEx sequence SpraySystemExclusive(sysexBuf, sysexSize, timestamp); haveSysEx = false; if (next == B_SYS_EX_END) { // swallow SysEx end byte continue; } // any other byte, while ending the SysEx sequence, // should be handled, not dropped } } if ((next & 0xF8) == 0xF8) { // System Realtime SpraySystemRealTime(next, timestamp); } else if ((next & 0xF0) == 0xF0) { // System Common runningStatus = 0; msgBuf[0] = next; msgPtr = msgBuf + 1; switch (next) { case B_SYS_EX_START: sysexAlloc = 4096; sysexBuf = (uint8*) malloc(sysexAlloc); sysexSize = 0; haveSysEx = true; break; case B_SONG_POSITION: needed = 2; msgSize = 3; break; case B_MIDI_TIME_CODE: case B_SONG_SELECT: case B_CABLE_MESSAGE: needed = 1; msgSize = 2; break; case B_SYS_EX_END: // Unpaired with B_SYS_EX_START, but pass it anyway... case B_TUNE_REQUEST: SpraySystemCommon(next, 0, 0, timestamp); break; } } else if ((next & 0x80) == 0x80) { // Voice message runningStatus = next; msgBuf[0] = next; msgPtr = msgBuf + 1; switch (next & 0xF0) { case B_NOTE_OFF: case B_NOTE_ON: case B_KEY_PRESSURE: case B_CONTROL_CHANGE: case B_PITCH_BEND: needed = 2; msgSize = 3; break; case B_PROGRAM_CHANGE: case B_CHANNEL_PRESSURE: needed = 1; msgSize = 2; break; } } else if (needed > 0) { // Data bytes to complete message *msgPtr++ = next; if (--needed == 0) { switch (msgBuf[0] & 0xF0) { case B_NOTE_OFF: SprayNoteOff(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2], timestamp); break; case B_NOTE_ON: SprayNoteOn(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2], timestamp); break; case B_KEY_PRESSURE: SprayKeyPressure(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2], timestamp); break; case B_CONTROL_CHANGE: SprayControlChange(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2], timestamp); break; case B_PROGRAM_CHANGE: SprayProgramChange(msgBuf[0] & 0x0F, msgBuf[1], timestamp); break; case B_CHANNEL_PRESSURE: SprayChannelPressure(msgBuf[0] & 0x0F, msgBuf[1], timestamp); break; case B_PITCH_BEND: SprayPitchBend(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2], timestamp); break; } switch (msgBuf[0]) { case B_SONG_POSITION: SpraySystemCommon(msgBuf[0], msgBuf[1], msgBuf[2], timestamp); break; case B_MIDI_TIME_CODE: case B_SONG_SELECT: case B_CABLE_MESSAGE: SpraySystemCommon(msgBuf[0], msgBuf[1], 0, timestamp); break; } } } else if (runningStatus != 0) { // Repeated voice command msgBuf[0] = runningStatus; msgBuf[1] = next; msgPtr = msgBuf + 2; needed = msgSize - 2; } } // while fKeepRunning if (haveSysEx) free(sysexBuf); return fKeepRunning ? errno : B_OK; }