diff --git a/src/BLEMIDI_Transport.h b/src/BLEMIDI_Transport.h index a26f9b8..749574c 100644 --- a/src/BLEMIDI_Transport.h +++ b/src/BLEMIDI_Transport.h @@ -10,10 +10,12 @@ #include "BLEMIDI_Defs.h" #include "BLEMIDI_Namespace.h" -// #define CHECK_BIT(var, pos) (!!((var) & (1 << (pos)))) - BEGIN_BLEMIDI_NAMESPACE +using namespace MIDI_NAMESPACE; + +#define MIDI_TYPE 0x80 + template class BLEMIDI_Transport { @@ -77,7 +79,7 @@ public: void endTransmission() { - if (mTxBuffer[mTxIndex - 1] == MIDI_NAMESPACE::MidiType::SystemExclusiveEnd) + if (mTxBuffer[mTxIndex - 1] == SystemExclusiveEnd) { if (mTxIndex >= sizeof(mTxBuffer)) { @@ -90,7 +92,7 @@ public: { mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ? } - mTxBuffer[mTxIndex++] = MIDI_NAMESPACE::MidiType::SystemExclusiveEnd; + mTxBuffer[mTxIndex++] = SystemExclusiveEnd; } mBleClass.write(mTxBuffer, mTxIndex); @@ -110,7 +112,6 @@ public: return mRxIndex; mRxBuffer[mRxIndex++] = byte; - return mRxIndex; } @@ -221,6 +222,14 @@ public: MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved 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) { // Pointers used to search through payload. @@ -229,107 +238,157 @@ public: // lastStatus used to capture runningStatus byte lastStatus; + // previousStatus used to continue a runningStatus interrupted by a timeStamp or a System Message. + byte previousStatus = InvalidType; 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; byte timestampByte = buffer[lPtr++]; uint16_t timestamp = 0; 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); + // what do to with the timestamp? } else // if bit 7 is 0, it's the Continuation of a previous SysEx { 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) { lastStatus = buffer[lPtr]; - if ((buffer[lPtr] < 0x80) && !sysExContinuation) - return; // Status message not present, bail + if (previousStatus == InvalidType) + { + 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 rPtr = lPtr; - while ((buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1))) + while ((buffer[rPtr + 1] < MIDI_TYPE) && (rPtr < (length - 1))) rPtr++; - // look at l and r pointers and decode by size. - if (rPtr - lPtr < 1) + if (!runningStatusContinuation) { - // 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 + + auto midiType = lastStatus & 0xF0; + if (sysExContinuation) + midiType = SystemExclusive; + switch (midiType) { - case MIDI_NAMESPACE::MidiType::NoteOff: - case MIDI_NAMESPACE::MidiType::NoteOn: - case MIDI_NAMESPACE::MidiType::AfterTouchPoly: - case MIDI_NAMESPACE::MidiType::ControlChange: - case MIDI_NAMESPACE::MidiType::PitchBend: + case NoteOff: + case NoteOn: + case AfterTouchPoly: + case ControlChange: + case PitchBend: +#ifdef RUNNING_ENABLE + mBleClass.add(lastStatus); +#endif for (auto i = lPtr; i < rPtr; i = i + 2) { +#ifndef RUNNING_ENABLE mBleClass.add(lastStatus); +#endif mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 2]); } break; - case MIDI_NAMESPACE::MidiType::ProgramChange: - case MIDI_NAMESPACE::MidiType::AfterTouchChannel: + case ProgramChange: + case AfterTouchChannel: +#ifdef RUNNING_ENABLE + mBleClass.add(lastStatus); +#endif for (auto i = lPtr; i < rPtr; i = i + 1) { +#ifndef RUNNING_ENABLE mBleClass.add(lastStatus); +#endif mBleClass.add(buffer[i + 1]); } break; - case MIDI_NAMESPACE::MidiType::SystemExclusive: - - mBleClass.add(buffer[lPtr]); + case SystemExclusive: + mBleClass.add(lastStatus); for (auto i = lPtr; i < rPtr; i++) mBleClass.add(buffer[i + 1]); break; + default: 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) return; // end of packet - timestampByte = buffer[rPtr++]; - if (timestampByte >= 80) // is bit 7 set? + if (lastStatus < SystemExclusive) //exclude System Message. They must not be RunningStatus { - 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? }