Modified received(). Running Status and divided SysEx are accepted

This commit is contained in:
Roberto 2021-08-04 17:39:48 +02:00
parent 5a0fd77bc6
commit 4e52f70062
1 changed files with 179 additions and 77 deletions

View File

@ -12,7 +12,7 @@
BEGIN_BLEMIDI_NAMESPACE BEGIN_BLEMIDI_NAMESPACE
template<class T, class _Settings = DefaultSettings> template <class T, class _Settings = DefaultSettings>
class BLEMIDI_Transport class BLEMIDI_Transport
{ {
typedef _Settings Settings; typedef _Settings Settings;
@ -29,16 +29,16 @@ private:
uint8_t mTimestampLow; uint8_t mTimestampLow;
private: private:
T mBleClass; T mBleClass;
public: public:
BLEMIDI_Transport(const char* deviceName) BLEMIDI_Transport(const char *deviceName)
{ {
strncpy(mDeviceName, deviceName, sizeof(mDeviceName)); strncpy(mDeviceName, deviceName, sizeof(mDeviceName));
mRxIndex = 0; mRxIndex = 0;
mTxIndex = 0; mTxIndex = 0;
} }
public: public:
static const bool thruActivated = false; static const bool thruActivated = false;
@ -76,7 +76,7 @@ public:
{ {
mBleClass.write(mTxBuffer, mTxIndex - 1); mBleClass.write(mTxBuffer, mTxIndex - 1);
mTxIndex = 1; // keep header mTxIndex = 1; // keep header
mTxBuffer[mTxIndex++] = mTimestampLow; // or generate new ? mTxBuffer[mTxIndex++] = mTimestampLow; // or generate new ?
} }
else else
@ -95,14 +95,19 @@ public:
return mRxBuffer[--mRxIndex]; return mRxBuffer[--mRxIndex];
} }
bool end()
{
return mBleClass.end();
}
unsigned available() unsigned available()
{ {
uint8_t byte; uint8_t byte;
auto success = mBleClass.available(&byte); auto success = mBleClass.available(&byte);
if (!success) return mRxIndex; if (!success)
return mRxIndex;
mRxBuffer[mRxIndex++] = byte; mRxBuffer[mRxIndex++] = byte;
return mRxIndex; return mRxIndex;
} }
@ -152,31 +157,33 @@ protected:
and the MSB of both bytes are set to indicate that this is a header byte. and the MSB of both bytes are set to indicate that this is a header byte.
Both bytes are placed into the first two position of an array in preparation for a MIDI message. Both bytes are placed into the first two position of an array in preparation for a MIDI message.
*/ */
static void getMidiTimestamp (uint8_t *header, uint8_t *timestamp) static void getMidiTimestamp(uint8_t *header, uint8_t *timestamp)
{ {
auto currentTimeStamp = millis() & 0x01FFF; auto currentTimeStamp = millis() & 0x01FFF;
*header = ((currentTimeStamp >> 7) & 0x3F) | 0x80; // 6 bits plus MSB *header = ((currentTimeStamp >> 7) & 0x3F) | 0x80; // 6 bits plus MSB
*timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB *timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB
} }
static void setMidiTimestamp (uint8_t header, uint8_t *timestamp) static void setMidiTimestamp(uint8_t header, uint8_t *timestamp)
{ {
} }
public: public:
// callbacks // callbacks
void(*_connectedCallback)() = nullptr; void (*_connectedCallback)() = nullptr;
void(*_disconnectedCallback)() = nullptr; void (*_disconnectedCallback)() = nullptr;
public: public:
void setHandleConnected(void(*fptr)()) { void setHandleConnected(void (*fptr)())
_connectedCallback = fptr; {
} _connectedCallback = fptr;
}
void setHandleDisconnected(void(*fptr)()) { void setHandleDisconnected(void (*fptr)())
_disconnectedCallback = fptr; {
} _disconnectedCallback = fptr;
}
/* /*
The general form of a MIDI message follows: The general form of a MIDI message follows:
@ -208,83 +215,179 @@ 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.
*/ */
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.
byte lPtr = 0; int lPtr = 0;
byte rPtr = 0; int rPtr = 0;
// lastStatus used to capture runningStatus // lastStatus used to capture runningStatus
byte lastStatus; byte lastStatus;
// Decode first packet -- SHALL be "Full MIDI message" // previousStatus used to continue a runningStatus interrupted by a timeStamp or a System Message.
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" byte previousStatus = 0x00;
byte headerByte = buffer[lPtr++];
auto timestampHigh = 0x3f & headerByte;
byte timestampByte = buffer[lPtr++];
uint16_t timestamp = 0;
bool sysExContinuation = false;
bool runningStatusContinuation = false;
if (timestampByte >= 80)
{
auto timestampLow = 0x7f & timestampByte;
timestamp = timestampLow + (timestampHigh << 7);
}
else
{
sysExContinuation = true;
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)) 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++;
if (buffer[rPtr + 1] == 0xF7) rPtr++;
// look at l and r pointers and decode by size. if (!runningStatusContinuation)
if( rPtr - lPtr < 1 ) { {
// Time code or system // look at l and r pointers and decode by size.
mBleClass.add(lastStatus); if (rPtr - lPtr < 1)
} else if( rPtr - lPtr < 2 ) { {
mBleClass.add(lastStatus); // Time code or system
mBleClass.add(buffer[lPtr + 1]); mBleClass.add(buffer[lPtr]);
} else if( rPtr - lPtr < 3 ) { }
mBleClass.add(lastStatus); else if (rPtr - lPtr < 2)
mBleClass.add(buffer[lPtr + 1]); {
mBleClass.add(buffer[lPtr + 2]); mBleClass.add(buffer[lPtr]);
} else { mBleClass.add(buffer[lPtr + 1]);
// Too much data }
// If not System Common or System Real-Time, send it as running status else if (rPtr - lPtr < 3)
switch(buffer[lPtr] & 0xF0) {
mBleClass.add(buffer[lPtr]);
mBleClass.add(buffer[lPtr + 1]);
mBleClass.add(buffer[lPtr + 2]);
}
else
{
// Too much data
// If not System Common or System Real-Time, send it as running status
auto midiType = lastStatus & 0xF0;
if (sysExContinuation)
midiType = 0xF0;
switch (midiType)
{
case 0x80:
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
for (auto i = lPtr; i < rPtr; i = i + 2)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i + 1]);
mBleClass.add(buffer[i + 2]);
}
break;
case 0xC0:
case 0xD0:
for (auto i = lPtr; i < rPtr; i = i + 1)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i + 1]);
}
break;
case 0xF0:
mBleClass.add(lastStatus);
for (auto i = lPtr; i < rPtr; i++)
mBleClass.add(buffer[i + 1]);
break;
default:
break;
}
}
}
else
{
auto midiType = lastStatus & 0xF0;
if (sysExContinuation)
midiType = 0xF0;
switch (midiType)
{ {
case 0x80: case 0x80:
case 0x90: case 0x90:
case 0xA0: case 0xA0:
case 0xB0: case 0xB0:
case 0xE0: case 0xE0:
for (auto i = lPtr; i < rPtr; i = i + 2) //3 bytes full Midi -> 2 bytes runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 2)
{ {
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
mBleClass.add(buffer[i]);
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 1]);
mBleClass.add(buffer[i + 2]);
} }
break; break;
case 0xC0: case 0xC0:
case 0xD0: case 0xD0:
for (auto i = lPtr; i < rPtr; i = i + 1) //2 bytes full Midi -> 1 byte runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 1)
{ {
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i]);
} }
break; break;
case 0xF0:
mBleClass.add(buffer[lPtr]);
for (auto i = lPtr; i < rPtr; i++)
mBleClass.add(buffer[i + 1]);
break;
default: default:
break; break;
} }
runningStatusContinuation = false;
}
if (++rPtr >= length)
return; // end of packet
if (lastStatus < 0xf0) //exclude System Message. They must not be RunningStatus
{
previousStatus = lastStatus;
}
timestampByte = buffer[rPtr++];
if (timestampByte >= 80) // is bit 7 set?
{
auto timestampLow = 0x7f & timestampByte;
timestamp = timestampLow + (timestampHigh << 7);
} }
// Point to next status // Point to next status
lPtr = rPtr + 2; lPtr = rPtr;
if(lPtr >= length) if (lPtr >= length)
return; //end of packet return; //end of packet
} }
} }
}; };
struct MySettings : public MIDI_NAMESPACE::DefaultSettings struct MySettings : public MIDI_NAMESPACE::DefaultSettings
@ -293,4 +396,3 @@ struct MySettings : public MIDI_NAMESPACE::DefaultSettings
}; };
END_BLEMIDI_NAMESPACE END_BLEMIDI_NAMESPACE