Update parser

Parser is more simple now. It not evaluate the size of package twice.
Parser not check if a message is well constructed or not except first message of the package. 
Parser can transform runningStatus messages to Full Midi messages. If #define RUNNING_ENABLE is commented, parser will add data like full midi messages. 
FortySevenEffects MIDI serial parser respond identically to both method (runningStatus and Full), fortunately.
This commit is contained in:
RobertoHE 2021-08-05 21:30:44 +02:00 committed by GitHub
parent fa85454114
commit 335cad374d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 104 additions and 49 deletions

View File

@ -10,8 +10,6 @@
#include "BLEMIDI_Defs.h" #include "BLEMIDI_Defs.h"
#include "BLEMIDI_Namespace.h" #include "BLEMIDI_Namespace.h"
// #define CHECK_BIT(var, pos) (!!((var) & (1 << (pos))))
BEGIN_BLEMIDI_NAMESPACE BEGIN_BLEMIDI_NAMESPACE
template <class T, class _Settings = DefaultSettings> template <class T, class _Settings = DefaultSettings>
@ -49,7 +47,7 @@ public:
{ {
mBleClass.begin(mDeviceName, this); mBleClass.begin(mDeviceName, this);
} }
void end() void end()
{ {
mBleClass.end(); mBleClass.end();
@ -77,7 +75,7 @@ public:
void endTransmission() void endTransmission()
{ {
if (mTxBuffer[mTxIndex - 1] == MIDI_NAMESPACE::MidiType::SystemExclusiveEnd) if (mTxBuffer[mTxIndex - 1] == 0xF7)
{ {
if (mTxIndex >= sizeof(mTxBuffer)) if (mTxIndex >= sizeof(mTxBuffer))
{ {
@ -90,7 +88,7 @@ public:
{ {
mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ? mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ?
} }
mTxBuffer[mTxIndex++] = MIDI_NAMESPACE::MidiType::SystemExclusiveEnd; mTxBuffer[mTxIndex++] = 0xF7;
} }
mBleClass.write(mTxBuffer, mTxIndex); mBleClass.write(mTxBuffer, mTxIndex);
@ -110,7 +108,6 @@ public:
return mRxIndex; return mRxIndex;
mRxBuffer[mRxIndex++] = byte; mRxBuffer[mRxIndex++] = byte;
return mRxIndex; return mRxIndex;
} }
@ -221,6 +218,14 @@ public:
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
from other messages except for System Exclusive messages. from other messages except for System Exclusive messages.
*/ */
/**
* If #define RUNNING_ENABLE is commented, it will transform all incoming runningStatus messages in full midi messages.
* Else, it will put in the buffer the same info that it had received (runningStatus will be not transformated).
* It recommend not use runningStatus by default. Only use if parser accepts runningStatus and your application has a so high transmission rate.
*/
//#define RUNNING_ENABLE
void receive(byte *buffer, size_t length) void receive(byte *buffer, size_t length)
{ {
// Pointers used to search through payload. // Pointers used to search through payload.
@ -229,108 +234,158 @@ public:
// lastStatus used to capture runningStatus // lastStatus used to capture runningStatus
byte lastStatus; byte lastStatus;
// previousStatus used to continue a runningStatus interrupted by a timeStamp or a System Message.
byte previousStatus = 0x00;
byte headerByte = buffer[lPtr++]; byte headerByte = buffer[lPtr++];
// auto signatureIs1 = CHECK_BIT(headerByte, 7 - 1); // must be 1
// auto reservedIs0 = !CHECK_BIT(headerByte, 6 - 1); // must be 0
auto timestampHigh = 0x3f & headerByte; auto timestampHigh = 0x3f & headerByte;
byte timestampByte = buffer[lPtr++]; byte timestampByte = buffer[lPtr++];
uint16_t timestamp = 0; uint16_t timestamp = 0;
bool sysExContinuation = false; bool sysExContinuation = false;
bool runningStatusContinuation = false;
if (timestampByte >= 80) // if bit 7 is 1, it's a timestampByte if (timestampByte >= 80) // if bit 7 is 1, it's a timestampByte
{ {
timestamp = setMidiTimestamp(headerByte, timestampByte); auto timestampLow = 0x7f & timestampByte;
timestamp = timestampLow + (timestampHigh << 7);
} }
else // if bit 7 is 0, it's the Continuation of a previous SysEx else // if bit 7 is 0, it's the Continuation of a previous SysEx
{ {
sysExContinuation = true; sysExContinuation = true;
lPtr--; lPtr--; // the second byte is part of the SysEx
} }
// While statement contains incrementing pointers and breaks when buffer size exceeded. //While statement contains incrementing pointers and breaks when buffer size exceeded.
while (true) while (true)
{ {
lastStatus = buffer[lPtr]; lastStatus = buffer[lPtr];
if ((buffer[lPtr] < 0x80) && !sysExContinuation) if (previousStatus == 0x00)
return; // Status message not present, bail {
if ((lastStatus < 0x80) && !sysExContinuation)
return; // Status message not present and it is not a runningStatus continuation, bail
}
else if (lastStatus < 0x80)
{
lastStatus = previousStatus;
runningStatusContinuation = true;
}
// Point to next non-data byte // Point to next non-data byte
rPtr = lPtr; rPtr = lPtr;
while ((buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1))) while ((buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)))
rPtr++; rPtr++;
// look at l and r pointers and decode by size. if (!runningStatusContinuation)
if (rPtr - lPtr < 1)
{ {
// Time code or system
mBleClass.add(lastStatus);
}
else if (rPtr - lPtr < 2)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[lPtr + 1]);
}
else if (rPtr - lPtr < 3)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[lPtr + 1]);
mBleClass.add(buffer[lPtr + 2]);
}
else
{
auto midiType = buffer[lPtr] & 0xF0;
if (sysExContinuation)
midiType = MIDI_NAMESPACE::MidiType::SystemExclusive;
// Too much data
// If not System Common or System Real-Time, send it as running status // If not System Common or System Real-Time, send it as running status
auto midiType = lastStatus & 0xF0;
if (sysExContinuation)
midiType = 0xF0;
switch (midiType) switch (midiType)
{ {
case MIDI_NAMESPACE::MidiType::NoteOff: case 0x80:
case MIDI_NAMESPACE::MidiType::NoteOn: case 0x90:
case MIDI_NAMESPACE::MidiType::AfterTouchPoly: case 0xA0:
case MIDI_NAMESPACE::MidiType::ControlChange: case 0xB0:
case MIDI_NAMESPACE::MidiType::PitchBend: case 0xE0:
#ifdef RUNNING_ENABLE
mBleClass.add(lastStatus);
#endif
for (auto i = lPtr; i < rPtr; i = i + 2) for (auto i = lPtr; i < rPtr; i = i + 2)
{ {
#ifndef RUNNING_ENABLE
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
#endif
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 1]);
mBleClass.add(buffer[i + 2]); mBleClass.add(buffer[i + 2]);
} }
break; break;
case MIDI_NAMESPACE::MidiType::ProgramChange: case 0xC0:
case MIDI_NAMESPACE::MidiType::AfterTouchChannel: case 0xD0:
#ifdef RUNNING_ENABLE
mBleClass.add(lastStatus);
#endif
for (auto i = lPtr; i < rPtr; i = i + 1) for (auto i = lPtr; i < rPtr; i = i + 1)
{ {
#ifndef RUNNING_ENABLE
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
#endif
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 1]);
} }
break; break;
case MIDI_NAMESPACE::MidiType::SystemExclusive: case 0xF0:
mBleClass.add(lastStatus);
mBleClass.add(buffer[lPtr]);
for (auto i = lPtr; i < rPtr; i++) for (auto i = lPtr; i < rPtr; i++)
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 1]);
break; break;
default: default:
break; break;
} }
} }
else
{
#ifndef RUNNING_ENABLE
auto midiType = lastStatus & 0xF0;
if (sysExContinuation)
midiType = 0xF0;
switch (midiType)
{
case 0x80:
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
//3 bytes full Midi -> 2 bytes runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 2)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i]);
mBleClass.add(buffer[i + 1]);
}
break;
case 0xC0:
case 0xD0:
//2 bytes full Midi -> 1 byte runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 1)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i]);
}
break;
default:
break;
}
#else
mBleClass.add(lastStatus);
for (auto i = lPtr; i <= rPtr; i++)
mBleClass.add(buffer[i]);
#endif
runningStatusContinuation = false;
}
if (++rPtr >= length) if (++rPtr >= length)
return; // end of packet return; // end of packet
if (lastStatus < 0xf0) //exclude System Message. They must not be RunningStatus
{
previousStatus = lastStatus;
}
timestampByte = buffer[rPtr++]; timestampByte = buffer[rPtr++];
if (timestampByte >= 80) // is bit 7 set? if (timestampByte >= 80) // is bit 7 set?
{ {
timestamp = setMidiTimestamp(headerByte, timestampByte); auto timestampLow = 0x7f & timestampByte;
// what do to with the timestamp? timestamp = timestampLow + (timestampHigh << 7);
} }
// Point to next status // Point to next status