| @@ -33,79 +33,68 @@ namespace juce | |||
| class MidiDataConcatenator | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| MidiDataConcatenator (int initialBufferSize) | |||
| : pendingData ((size_t) initialBufferSize) | |||
| : pendingSysexData ((size_t) initialBufferSize) | |||
| { | |||
| } | |||
| void reset() | |||
| { | |||
| pendingBytes = 0; | |||
| runningStatus = 0; | |||
| pendingDataTime = 0; | |||
| currentMessageLen = 0; | |||
| pendingSysexSize = 0; | |||
| pendingSysexTime = 0; | |||
| } | |||
| template <typename UserDataType, typename CallbackType> | |||
| void pushMidiData (const void* inputData, int numBytes, double time, | |||
| UserDataType* input, CallbackType& callback) | |||
| { | |||
| const uint8* d = static_cast<const uint8*> (inputData); | |||
| auto d = static_cast<const uint8*> (inputData); | |||
| while (numBytes > 0) | |||
| { | |||
| if (pendingBytes > 0 || d[0] == 0xf0) | |||
| auto nextByte = *d; | |||
| if (pendingSysexSize != 0 || nextByte == 0xf0) | |||
| { | |||
| processSysex (d, numBytes, time, input, callback); | |||
| runningStatus = 0; | |||
| currentMessageLen = 0; | |||
| continue; | |||
| } | |||
| else | |||
| { | |||
| int len = 0; | |||
| uint8 data[3]; | |||
| while (numBytes > 0) | |||
| { | |||
| // If there's a realtime message embedded in the middle of | |||
| // the normal message, handle it now.. | |||
| if (*d >= 0xf8 && *d <= 0xfe) | |||
| { | |||
| callback.handleIncomingMidiMessage (input, MidiMessage (*d++, time)); | |||
| --numBytes; | |||
| } | |||
| else | |||
| { | |||
| if (len == 0 && *d < 0x80 && runningStatus >= 0x80) | |||
| data[len++] = runningStatus; | |||
| data[len++] = *d++; | |||
| --numBytes; | |||
| const uint8 firstByte = data[0]; | |||
| ++d; | |||
| --numBytes; | |||
| if (firstByte < 0x80 || firstByte == 0xf7) | |||
| { | |||
| len = 0; | |||
| break; // ignore this malformed MIDI message.. | |||
| } | |||
| if (nextByte >= 0xf8 && nextByte <= 0xfe) // realtime message | |||
| { | |||
| callback.handleIncomingMidiMessage (input, MidiMessage (nextByte, time)); | |||
| // These can be embedded in the middle of a normal message, so we won't | |||
| // reset the currentMessageLen here. | |||
| continue; | |||
| } | |||
| if (len >= MidiMessage::getMessageLengthFromFirstByte (firstByte)) | |||
| break; | |||
| } | |||
| if (nextByte < 0x80) | |||
| { | |||
| if (currentMessageLen == 3) | |||
| { | |||
| currentMessageLen = 0; // message is too long - abandon it and start again with the next byte | |||
| continue; | |||
| } | |||
| if (len > 0) | |||
| { | |||
| int used = 0; | |||
| const MidiMessage m (data, len, used, 0, time); | |||
| currentMessage[currentMessageLen++] = nextByte; | |||
| } | |||
| else | |||
| { | |||
| currentMessage[0] = nextByte; | |||
| currentMessageLen = 1; | |||
| } | |||
| if (used <= 0) | |||
| break; // malformed message.. | |||
| auto expectedLength = MidiMessage::getMessageLengthFromFirstByte (currentMessage[0]); | |||
| jassert (used == len); | |||
| callback.handleIncomingMidiMessage (input, m); | |||
| runningStatus = data[0]; | |||
| } | |||
| if (expectedLength == currentMessageLen) | |||
| { | |||
| callback.handleIncomingMidiMessage (input, MidiMessage (currentMessage, expectedLength)); | |||
| currentMessageLen = 1; // reset, but leave the first byte to use as the running status byte | |||
| } | |||
| } | |||
| } | |||
| @@ -117,22 +106,22 @@ private: | |||
| { | |||
| if (*d == 0xf0) | |||
| { | |||
| pendingBytes = 0; | |||
| pendingDataTime = time; | |||
| pendingSysexSize = 0; | |||
| pendingSysexTime = time; | |||
| } | |||
| pendingData.ensureSize ((size_t) (pendingBytes + numBytes), false); | |||
| uint8* totalMessage = static_cast<uint8*> (pendingData.getData()); | |||
| uint8* dest = totalMessage + pendingBytes; | |||
| pendingSysexData.ensureSize ((size_t) (pendingSysexSize + numBytes), false); | |||
| auto totalMessage = static_cast<uint8*> (pendingSysexData.getData()); | |||
| auto dest = totalMessage + pendingSysexSize; | |||
| do | |||
| { | |||
| if (pendingBytes > 0 && *d >= 0x80) | |||
| if (pendingSysexSize > 0 && *d >= 0x80) | |||
| { | |||
| if (*d == 0xf7) | |||
| { | |||
| *dest++ = *d++; | |||
| ++pendingBytes; | |||
| ++pendingSysexSize; | |||
| --numBytes; | |||
| break; | |||
| } | |||
| @@ -145,7 +134,7 @@ private: | |||
| } | |||
| else | |||
| { | |||
| pendingBytes = 0; | |||
| pendingSysexSize = 0; | |||
| int used = 0; | |||
| const MidiMessage m (d, numBytes, used, 0, time); | |||
| @@ -162,30 +151,32 @@ private: | |||
| else | |||
| { | |||
| *dest++ = *d++; | |||
| ++pendingBytes; | |||
| ++pendingSysexSize; | |||
| --numBytes; | |||
| } | |||
| } | |||
| while (numBytes > 0); | |||
| if (pendingBytes > 0) | |||
| if (pendingSysexSize > 0) | |||
| { | |||
| if (totalMessage [pendingBytes - 1] == 0xf7) | |||
| if (totalMessage [pendingSysexSize - 1] == 0xf7) | |||
| { | |||
| callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); | |||
| pendingBytes = 0; | |||
| callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingSysexSize, pendingSysexTime)); | |||
| pendingSysexSize = 0; | |||
| } | |||
| else | |||
| { | |||
| callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); | |||
| callback.handlePartialSysexMessage (input, totalMessage, pendingSysexSize, pendingSysexTime); | |||
| } | |||
| } | |||
| } | |||
| MemoryBlock pendingData; | |||
| double pendingDataTime = 0; | |||
| int pendingBytes = 0; | |||
| uint8 runningStatus = 0; | |||
| uint8 currentMessage[3] = {}; | |||
| int currentMessageLen = 0; | |||
| MemoryBlock pendingSysexData; | |||
| double pendingSysexTime = 0; | |||
| int pendingSysexSize = 0; | |||
| JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator) | |||
| }; | |||