commit
c20062ec63
|
|
@ -10,10 +10,12 @@
|
||||||
#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
|
||||||
|
|
||||||
|
using namespace MIDI_NAMESPACE;
|
||||||
|
|
||||||
|
#define MIDI_TYPE 0x80
|
||||||
|
|
||||||
template <class T, class _Settings = DefaultSettings>
|
template <class T, class _Settings = DefaultSettings>
|
||||||
class BLEMIDI_Transport
|
class BLEMIDI_Transport
|
||||||
{
|
{
|
||||||
|
|
@ -77,7 +79,7 @@ public:
|
||||||
|
|
||||||
void endTransmission()
|
void endTransmission()
|
||||||
{
|
{
|
||||||
if (mTxBuffer[mTxIndex - 1] == MIDI_NAMESPACE::MidiType::SystemExclusiveEnd)
|
if (mTxBuffer[mTxIndex - 1] == SystemExclusiveEnd)
|
||||||
{
|
{
|
||||||
if (mTxIndex >= sizeof(mTxBuffer))
|
if (mTxIndex >= sizeof(mTxBuffer))
|
||||||
{
|
{
|
||||||
|
|
@ -90,7 +92,7 @@ public:
|
||||||
{
|
{
|
||||||
mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ?
|
mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ?
|
||||||
}
|
}
|
||||||
mTxBuffer[mTxIndex++] = MIDI_NAMESPACE::MidiType::SystemExclusiveEnd;
|
mTxBuffer[mTxIndex++] = SystemExclusiveEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBleClass.write(mTxBuffer, mTxIndex);
|
mBleClass.write(mTxBuffer, mTxIndex);
|
||||||
|
|
@ -110,7 +112,6 @@ public:
|
||||||
return mRxIndex;
|
return mRxIndex;
|
||||||
|
|
||||||
mRxBuffer[mRxIndex++] = byte;
|
mRxBuffer[mRxIndex++] = byte;
|
||||||
|
|
||||||
return mRxIndex;
|
return mRxIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,6 +222,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,107 +238,157 @@ 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 = InvalidType;
|
||||||
|
|
||||||
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 >= MIDI_TYPE) // if bit 7 is 1, it's a timestampByte
|
||||||
{
|
{
|
||||||
timestamp = setMidiTimestamp(headerByte, timestampByte);
|
timestamp = setMidiTimestamp(headerByte, timestampByte);
|
||||||
|
// what do to with the timestamp?
|
||||||
}
|
}
|
||||||
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 == InvalidType)
|
||||||
return; // Status message not present, bail
|
{
|
||||||
|
if ((lastStatus < MIDI_TYPE) && !sysExContinuation)
|
||||||
|
return; // Status message not present and it is not a runningStatus continuation, bail
|
||||||
|
}
|
||||||
|
else if (lastStatus < MIDI_TYPE)
|
||||||
|
{
|
||||||
|
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] < MIDI_TYPE) && (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 = SystemExclusive;
|
||||||
|
|
||||||
switch (midiType)
|
switch (midiType)
|
||||||
{
|
{
|
||||||
case MIDI_NAMESPACE::MidiType::NoteOff:
|
case NoteOff:
|
||||||
case MIDI_NAMESPACE::MidiType::NoteOn:
|
case NoteOn:
|
||||||
case MIDI_NAMESPACE::MidiType::AfterTouchPoly:
|
case AfterTouchPoly:
|
||||||
case MIDI_NAMESPACE::MidiType::ControlChange:
|
case ControlChange:
|
||||||
case MIDI_NAMESPACE::MidiType::PitchBend:
|
case PitchBend:
|
||||||
|
#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 ProgramChange:
|
||||||
case MIDI_NAMESPACE::MidiType::AfterTouchChannel:
|
case AfterTouchChannel:
|
||||||
|
#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 SystemExclusive:
|
||||||
|
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 = SystemExclusive;
|
||||||
|
|
||||||
|
switch (midiType)
|
||||||
|
{
|
||||||
|
case NoteOff:
|
||||||
|
case NoteOn:
|
||||||
|
case AfterTouchPoly:
|
||||||
|
case ControlChange:
|
||||||
|
case PitchBend:
|
||||||
|
//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 ProgramChange:
|
||||||
|
case AfterTouchChannel:
|
||||||
|
//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
|
||||||
|
|
||||||
timestampByte = buffer[rPtr++];
|
if (lastStatus < SystemExclusive) //exclude System Message. They must not be RunningStatus
|
||||||
if (timestampByte >= 80) // is bit 7 set?
|
|
||||||
{
|
{
|
||||||
timestamp = setMidiTimestamp(headerByte, timestampByte);
|
previousStatus = lastStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampByte = buffer[rPtr++];
|
||||||
|
if (timestampByte >= MIDI_TYPE) // is bit 7 set?
|
||||||
|
{
|
||||||
|
timestamp = setMidiTimestamp(headerByte, timestampByte);
|
||||||
// what do to with the timestamp?
|
// what do to with the timestamp?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue