Browse Source

Refactored MidiDataConcatenator to simplify its logic, and to make it handle breaks within the data stream of small midi messages

tags/2021-05-28
jules 7 years ago
parent
commit
d699f321b3
1 changed files with 57 additions and 66 deletions
  1. +57
    -66
      modules/juce_audio_devices/native/juce_MidiDataConcatenator.h

+ 57
- 66
modules/juce_audio_devices/native/juce_MidiDataConcatenator.h View File

@@ -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)
};


Loading…
Cancel
Save