// Each MIDIPacket can contain more than one midi messages. // This function processes the packet and adds the messages to the specified message queue. // @see also src/share/native/com/sun/media/sound/PlatformMidi.h. static void processMessagesForPacket(const MIDIPacket* packet, MacMidiDeviceHandle* handle) { const UInt8* data; UInt16 length; UInt8 byte; UInt8 pendingMessageStatus; UInt8 pendingData[2]; UInt16 pendingDataIndex, pendingDataLength; UINT32 packedMsg; MIDITimeStamp ts = packet->timeStamp; pendingMessageStatus = 0; pendingDataIndex = pendingDataLength = 0; data = packet->data; length = packet->length; while (length--) { bool byteIsInvalid = FALSE; byte = *data++; packedMsg = byte; if (byte >= 0xF8) { // Each RealTime Category message (ie, Status of 0xF8 to 0xFF) consists of only 1 byte, the Status. // Except that 0xFD is an invalid status code. // // 0xF8 -> Midi clock // 0xF9 -> Midi tick // 0xFA -> Midi start // 0xFB -> Midi continue // 0xFC -> Midi stop // 0xFE -> Active sense // 0xFF -> Reset if (byte == 0xFD) { byteIsInvalid = TRUE; } else { pendingDataLength = 0; } } else { if (byte < 0x80) { // Not a status byte -- check our history. if (handle->readingSysExData) { CFDataAppendBytes(handle->readingSysExData, &byte, 1); } else if (pendingDataIndex < pendingDataLength) { pendingData[pendingDataIndex] = byte; pendingDataIndex++; if (pendingDataIndex == pendingDataLength) { // This message is now done -- do the final processing. if (pendingDataLength == 2) { packedMsg = pendingMessageStatus | pendingData[0] << 8 | pendingData[1] << 16; } else if (pendingDataLength == 1) { packedMsg = pendingMessageStatus | pendingData[0] << 8; } else { fprintf(stderr, "%s: %d->internal error: pendingMessageStatus=0x%X, pendingDataLength=%d\n", __FILE__, __LINE__, pendingMessageStatus, pendingDataLength); byteIsInvalid = TRUE; } pendingDataLength = 0; } } else { // Skip this byte -- it is invalid. byteIsInvalid = TRUE; } } else { if (handle->readingSysExData /* && (byte == 0xF7) */) { // We have reached the end of system exclusive message -- send it finally. const UInt8* bytes = CFDataGetBytePtr(handle->readingSysExData); CFIndex size = CFDataGetLength(handle->readingSysExData); MIDI_QueueAddLong(handle->h.queue, (UBYTE*) bytes, (UINT32) size, 0, // Don't care, windowish porting only. (INT64) (AudioConvertHostTimeToNanos(ts) + 500) / 1000, TRUE); CFRelease(handle->readingSysExData); handle->readingSysExData = NULL; } pendingMessageStatus = byte; pendingDataLength = 0; pendingDataIndex = 0; switch (byte & 0xF0) { case 0x80: // Note off case 0x90: // Note on case 0xA0: // Aftertouch case 0xB0: // Controller case 0xE0: // Pitch wheel pendingDataLength = 2; break; case 0xC0: // Program change case 0xD0: // Channel pressure pendingDataLength = 1; break; case 0xF0: { // System common message switch (byte) { case 0xF0: // System exclusive // Allocates a CFMutableData reference to accumulate the SysEx data until EOX (0xF7) is reached. handle->readingSysExData = CFDataCreateMutable(NULL, 0); break; case 0xF7: // System exclusive ends--already handled above. // But if this is showing up outside of sysex, it's invalid. byteIsInvalid = TRUE; break; case 0xF1: // MTC quarter frame message case 0xF3: // Song select pendingDataLength = 1; break; case 0xF2: // Song position pointer pendingDataLength = 2; break; case 0xF6: // Tune request pendingDataLength = 0; break; default: // Invalid message byteIsInvalid = TRUE; break; } break; } default: // This can't happen, but handle it anyway. byteIsInvalid = TRUE; break; } } } if (byteIsInvalid) continue; // If the byte is valid and pendingDataLength is 0, we are ready to send the message. if (pendingDataLength == 0) { MIDI_QueueAddShort(handle->h.queue, packedMsg, (INT64) (AudioConvertHostTimeToNanos(ts) + 500) / 1000, TRUE); } } }
//$$fb dwParam1 holds a pointer for long messages. How can that be a DWORD then ??? void CALLBACK MIDI_IN_PutMessage( HMIDIIN hMidiIn, UINT wMsg, UINT_PTR dwInstance, UINT_PTR dwParam1, UINT_PTR dwParam2 ) { MidiDeviceHandle* handle = (MidiDeviceHandle*) dwInstance; TRACE3("> MIDI_IN_PutMessage, hMidiIn: %x, wMsg: %x, dwInstance: %x\n", hMidiIn, wMsg, dwInstance); TRACE2(" dwParam1: %x, dwParam2: %x\n", dwParam1, dwParam2); switch(wMsg) { case MIM_OPEN: TRACE0("< MIDI_IN_PutMessage: MIM_OPEN\n"); break; case MIM_CLOSE: TRACE0("< MIDI_IN_PutMessage: MIM_CLOSE\n"); break; case MIM_MOREDATA: case MIM_DATA: TRACE3(" MIDI_IN_PutMessage: MIM_MOREDATA or MIM_DATA. status=%x data1=%x data2=%x\n", dwParam1 & 0xFF, (dwParam1 & 0xFF00)>>8, (dwParam1 & 0xFF0000)>>16); if (handle!=NULL && handle->queue!=NULL && handle->platformData) { MIDI_QueueAddShort(handle->queue, // queue stores packedMsg in big endian //(dwParam1 << 24) | ((dwParam1 << 8) & 0xFF0000) | ((dwParam1 >> 8) & 0xFF00), (UINT32) dwParam1, // queue uses microseconds ((INT64) dwParam2)*1000, // overwrite if queue is full TRUE); SetEvent((HANDLE) handle->platformData); } TRACE0("< MIDI_IN_PutMessage\n"); break; case MIM_LONGDATA: TRACE1(" MIDI_IN_PutMessage: MIM_LONGDATA (%d bytes recorded)\n", (int) (((MIDIHDR*) dwParam1)->dwBytesRecorded)); if (handle!=NULL && handle->queue!=NULL && handle->platformData) { MIDIHDR* hdr = (MIDIHDR*) dwParam1; TRACE2(" MIDI_IN_PutMessage: Adding to queue: index %d, %d bytes\n", (INT32) hdr->dwUser, hdr->dwBytesRecorded); MIDI_QueueAddLong(handle->queue, (UBYTE*) hdr->lpData, (UINT32) hdr->dwBytesRecorded, // sysex buffer index (INT32) hdr->dwUser, // queue uses microseconds ((INT64) dwParam2)*1000, // overwrite if queue is full TRUE); SetEvent((HANDLE) handle->platformData); } TRACE0("< MIDI_IN_PutMessage\n"); break; case MIM_ERROR: ERROR0("< MIDI_IN_PutMessage: MIM_ERROR!\n"); break; case MIM_LONGERROR: if (dwParam1 != 0) { MIDIHDR* hdr = (MIDIHDR*) dwParam1; #ifdef USE_TRACE if (hdr->dwBytesRecorded > 0) { TRACE2(" MIDI_IN_PutMessage: MIM_LONGERROR! recorded: %d bytes with status 0x%2x\n", hdr->dwBytesRecorded, (int) (*((UBYTE*) hdr->lpData))); } #endif // re-add hdr to device query hdr->dwBytesRecorded = 0; midiInAddBuffer((HMIDIIN)handle->deviceHandle, hdr, sizeof(MIDIHDR)); } ERROR0("< MIDI_IN_PutMessage: MIM_LONGERROR!\n"); break; default: ERROR1("< MIDI_IN_PutMessage: ERROR unknown message %d!\n", wMsg); break; } // switch (wMsg) }