33 template<
class Transport,
class Settings,
class Platform>
35 : mTransport(inTransport)
39 , mPendingMessageExpectedLength(0)
40 , mPendingMessageIndex(0)
41 , mCurrentRpnNumber(0xffff)
42 , mCurrentNrpnNumber(0xffff)
43 , mThruActivated(true)
44 , mThruFilterMode(
Thru::Full)
45 , mLastMessageSentTime(0)
46 , mLastMessageReceivedTime(0)
47 , mSenderActiveSensingPeriodicity(0)
48 , mReceiverActiveSensingActivated(false)
51 mSenderActiveSensingPeriodicity = Settings::SenderActiveSensingPeriodicity;
58 template<
class Transport,
class Settings,
class Platform>
71 template<
class Transport,
class Settings,
class Platform>
77 mInputChannel = inChannel;
81 mPendingMessageIndex = 0;
82 mPendingMessageExpectedLength = 0;
84 mCurrentRpnNumber = 0xffff;
85 mCurrentNrpnNumber = 0xffff;
87 mLastMessageSentTime = Platform::now();
89 mMessage.valid =
false;
97 mThruActivated = mTransport.thruActivated;
117 template<
class Transport,
class Settings,
class Platform>
120 if (!inMessage.
valid)
123 if (mTransport.beginTransmission(inMessage.
type))
126 mTransport.write(status);
130 if (inMessage.
length > 1) mTransport.write(inMessage.
data1);
131 if (inMessage.
length > 2) mTransport.write(inMessage.
data2);
143 mTransport.endTransmission();
144 UpdateLastSentTime();
159 template<
class Transport,
class Settings,
class Platform>
178 const StatusByte status = getStatus(inType, inChannel);
180 if (mTransport.beginTransmission(inType))
182 if (Settings::UseRunningStatus)
184 if (mRunningStatus_TX != status)
187 mRunningStatus_TX = status;
188 mTransport.write(mRunningStatus_TX);
194 mTransport.write(status);
198 mTransport.write(inData1);
201 mTransport.write(inData2);
204 mTransport.endTransmission();
205 UpdateLastSentTime();
210 sendRealTime(inType);
225 template<
class Transport,
class Settings,
class Platform>
230 send(
NoteOn, inNoteNumber, inVelocity, inChannel);
244 template<
class Transport,
class Settings,
class Platform>
249 send(
NoteOff, inNoteNumber, inVelocity, inChannel);
256 template<
class Transport,
class Settings,
class Platform>
269 template<
class Transport,
class Settings,
class Platform>
274 send(
ControlChange, inControlNumber, inControlValue, inChannel);
284 template<
class Transport,
class Settings,
class Platform>
296 template<
class Transport,
class Settings,
class Platform>
309 template<
class Transport,
class Settings,
class Platform>
323 template<
class Transport,
class Settings,
class Platform>
328 send(
PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel);
338 template<
class Transport,
class Settings,
class Platform>
343 const int value = int(inPitchValue *
double(scale));
344 sendPitchBend(value, inChannel);
356 template<
class Transport,
class Settings,
class Platform>
359 bool inArrayContainsBoundaries)
361 const bool writeBeginEndBytes = !inArrayContainsBoundaries;
365 if (writeBeginEndBytes)
368 for (
unsigned i = 0; i < inLength; ++i)
369 mTransport.write(inArray[i]);
371 if (writeBeginEndBytes)
374 mTransport.endTransmission();
375 UpdateLastSentTime();
378 if (Settings::UseRunningStatus)
387 template<
class Transport,
class Settings,
class Platform>
399 template<
class Transport,
class Settings,
class Platform>
403 const byte data =
byte((((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)));
404 sendTimeCodeQuarterFrame(data);
413 template<
class Transport,
class Settings,
class Platform>
422 template<
class Transport,
class Settings,
class Platform>
429 template<
class Transport,
class Settings,
class Platform>
442 template<
class Transport,
class Settings,
class Platform>
457 if (mTransport.beginTransmission(inType))
459 mTransport.write((
byte)inType);
463 mTransport.write(inData1);
466 mTransport.write(inData1 & 0x7f);
467 mTransport.write((inData1 >> 7) & 0x7f);
470 mTransport.write(inData1 & 0x7f);
477 mTransport.endTransmission();
478 UpdateLastSentTime();
481 if (Settings::UseRunningStatus)
491 template<
class Transport,
class Settings,
class Platform>
505 if (mTransport.beginTransmission(inType))
507 mTransport.write((
byte)inType);
508 mTransport.endTransmission();
509 UpdateLastSentTime();
522 template<
class Transport,
class Settings,
class Platform>
526 if (mCurrentRpnNumber != inNumber)
528 const byte numMsb = 0x7f & (inNumber >> 7);
529 const byte numLsb = 0x7f & inNumber;
530 sendControlChange(
RPNLSB, numLsb, inChannel);
531 sendControlChange(
RPNMSB, numMsb, inChannel);
532 mCurrentRpnNumber = inNumber;
540 template<
class Transport,
class Settings,
class Platform>
544 const byte valMsb = 0x7f & (inValue >> 7);
545 const byte valLsb = 0x7f & inValue;
555 template<
class Transport,
class Settings,
class Platform>
567 template<
class Transport,
class Settings,
class Platform>
577 template<
class Transport,
class Settings,
class Platform>
588 template<
class Transport,
class Settings,
class Platform>
591 sendControlChange(
RPNLSB, 0x7f, inChannel);
592 sendControlChange(
RPNMSB, 0x7f, inChannel);
593 mCurrentRpnNumber = 0xffff;
602 template<
class Transport,
class Settings,
class Platform>
606 if (mCurrentNrpnNumber != inNumber)
608 const byte numMsb = 0x7f & (inNumber >> 7);
609 const byte numLsb = 0x7f & inNumber;
610 sendControlChange(
NRPNLSB, numLsb, inChannel);
611 sendControlChange(
NRPNMSB, numMsb, inChannel);
612 mCurrentNrpnNumber = inNumber;
620 template<
class Transport,
class Settings,
class Platform>
624 const byte valMsb = 0x7f & (inValue >> 7);
625 const byte valLsb = 0x7f & inValue;
635 template<
class Transport,
class Settings,
class Platform>
647 template<
class Transport,
class Settings,
class Platform>
657 template<
class Transport,
class Settings,
class Platform>
668 template<
class Transport,
class Settings,
class Platform>
671 sendControlChange(
NRPNLSB, 0x7f, inChannel);
672 sendControlChange(
NRPNMSB, 0x7f, inChannel);
673 mCurrentNrpnNumber = 0xffff;
680 template<
class Transport,
class Settings,
class Platform>
684 return StatusByte(((
byte)inType | ((inChannel - 1) & 0x0f)));
703 template<
class Transport,
class Settings,
class Platform>
706 return read(mInputChannel);
711 template<
class Transport,
class Settings,
class Platform>
714 #ifndef RegionActiveSending
723 if (Settings::UseSenderActiveSensing && (mSenderActiveSensingPeriodicity > 0) && (Platform::now() - mLastMessageSentTime) > mSenderActiveSensingPeriodicity)
726 mLastMessageSentTime = Platform::now();
729 if (Settings::UseReceiverActiveSensing && mReceiverActiveSensingActivated && (mLastMessageReceivedTime +
ActiveSensingTimeout < Platform::now()))
731 mReceiverActiveSensingActivated =
false;
735 mErrorCallback(mLastError);
745 #ifndef RegionActiveSending
747 if (Settings::UseReceiverActiveSensing && mMessage.type ==
ActiveSensing)
751 mReceiverActiveSensingActivated =
true;
758 mErrorCallback(mLastError);
763 if (Settings::UseReceiverActiveSensing && mReceiverActiveSensingActivated)
764 mLastMessageReceivedTime = Platform::now();
768 handleNullVelocityNoteOnAsNoteOff();
770 const bool channelMatch = inputFilter(inChannel);
774 thruFilter(inChannel);
782 template<
class Transport,
class Settings,
class Platform>
785 if (mTransport.available() == 0)
800 const byte extracted = mTransport.
read();
804 return (Settings::Use1ByteParsing) ? false : parse();
806 if (mPendingMessageIndex == 0)
809 mPendingMessage[0] = extracted;
812 if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
818 if (extracted < 0x80)
820 mPendingMessage[0] = mRunningStatus_RX;
821 mPendingMessage[1] = extracted;
822 mPendingMessageIndex = 1;
829 const MidiType pendingType = getTypeFromStatusByte(mPendingMessage[0]);
843 mMessage.type = pendingType;
844 mMessage.channel = 0;
847 mMessage.valid =
true;
851 mPendingMessageIndex = 0;
852 mPendingMessageExpectedLength = 0;
862 mPendingMessageExpectedLength = 2;
872 mPendingMessageExpectedLength = 3;
879 mPendingMessageExpectedLength = MidiMessage::sSysExMaxSize;
881 mMessage.sysexArray[0] = pendingType;
889 mErrorCallback(mLastError);
896 if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1))
899 mMessage.type = pendingType;
900 mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
901 mMessage.data1 = mPendingMessage[1];
905 mPendingMessageIndex = 0;
906 mPendingMessageExpectedLength = 0;
907 mMessage.valid =
true;
914 mPendingMessageIndex++;
917 return (Settings::Use1ByteParsing) ? false : parse();
922 if (extracted >= 0x80)
943 mMessage.type = (
MidiType)extracted;
946 mMessage.channel = 0;
948 mMessage.valid =
true;
959 mMessage.sysexArray[mPendingMessageIndex++] = extracted;
963 mMessage.data1 = mPendingMessageIndex & 0xff;
964 mMessage.data2 =
byte(mPendingMessageIndex >> 8);
965 mMessage.channel = 0;
966 mMessage.length = mPendingMessageIndex;
967 mMessage.valid =
true;
978 mErrorCallback(mLastError);
992 mMessage.sysexArray[mPendingMessageIndex] = extracted;
994 mPendingMessage[mPendingMessageIndex] = extracted;
997 if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1))
1007 auto lastByte = mMessage.sysexArray[Settings::SysExMaxSize - 1];
1012 mMessage.data1 = Settings::SysExMaxSize & 0xff;
1013 mMessage.data2 =
byte(Settings::SysExMaxSize >> 8);
1014 mMessage.channel = 0;
1015 mMessage.length = Settings::SysExMaxSize;
1016 mMessage.valid =
true;
1023 mMessage.sysexArray[1] = lastByte;
1025 mPendingMessageIndex = 2;
1030 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
1032 if (isChannelMessage(mMessage.type))
1033 mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
1035 mMessage.channel = 0;
1037 mMessage.data1 = mPendingMessage[1];
1039 mMessage.data2 = mPendingMessageExpectedLength == 3 ? mPendingMessage[2] : 0;
1042 mPendingMessageIndex = 0;
1043 mPendingMessageExpectedLength = 0;
1045 mMessage.valid =
true;
1048 switch (mMessage.type)
1058 mRunningStatus_RX = mPendingMessage[0];
1071 mPendingMessageIndex++;
1073 return (Settings::Use1ByteParsing) ? false : parse();
1079 template<
class Transport,
class Settings,
class Platform>
1082 if (Settings::HandleNullVelocityNoteOnAsNoteOff &&
1083 getType() ==
NoteOn && getData2() == 0)
1090 template<
class Transport,
class Settings,
class Platform>
1100 if ((mMessage.channel == inChannel) ||
1119 template<
class Transport,
class Settings,
class Platform>
1122 mPendingMessageIndex = 0;
1123 mPendingMessageExpectedLength = 0;
1133 template<
class Transport,
class Settings,
class Platform>
1136 return mMessage.type;
1144 template<
class Transport,
class Settings,
class Platform>
1147 return mMessage.channel;
1151 template<
class Transport,
class Settings,
class Platform>
1154 return mMessage.data1;
1158 template<
class Transport,
class Settings,
class Platform>
1161 return mMessage.data2;
1168 template<
class Transport,
class Settings,
class Platform>
1171 return mMessage.sysexArray;
1179 template<
class Transport,
class Settings,
class Platform>
1182 return mMessage.getSysExSize();
1186 template<
class Transport,
class Settings,
class Platform>
1189 return mMessage.valid;
1194 template<
class Transport,
class Settings,
class Platform>
1197 return mInputChannel;
1204 template<
class Transport,
class Settings,
class Platform>
1207 mInputChannel = inChannel;
1217 template<
class Transport,
class Settings,
class Platform>
1220 if ((inStatus < 0x80) ||
1226 if (inStatus < 0xf0)
1235 template<
class Transport,
class Settings,
class Platform>
1238 return Channel((inStatus & 0x0f) + 1);
1241 template<
class Transport,
class Settings,
class Platform>
1261 template<
class Transport,
class Settings,
class Platform>
1266 case NoteOff: mNoteOffCallback =
nullptr;
break;
1267 case NoteOn: mNoteOnCallback =
nullptr;
break;
1269 case ControlChange: mControlChangeCallback =
nullptr;
break;
1270 case ProgramChange: mProgramChangeCallback =
nullptr;
break;
1272 case PitchBend: mPitchBendCallback =
nullptr;
break;
1275 case SongPosition: mSongPositionCallback =
nullptr;
break;
1276 case SongSelect: mSongSelectCallback =
nullptr;
break;
1277 case TuneRequest: mTuneRequestCallback =
nullptr;
break;
1278 case Clock: mClockCallback =
nullptr;
break;
1279 case Start: mStartCallback =
nullptr;
break;
1280 case Tick: mTickCallback =
nullptr;
break;
1281 case Continue: mContinueCallback =
nullptr;
break;
1282 case Stop: mStopCallback =
nullptr;
break;
1283 case ActiveSensing: mActiveSensingCallback =
nullptr;
break;
1284 case SystemReset: mSystemResetCallback =
nullptr;
break;
1293 template<
class Transport,
class Settings,
class Platform>
1296 if (mMessageCallback != 0) mMessageCallback(mMessage);
1299 switch (mMessage.type)
1302 case NoteOff:
if (mNoteOffCallback !=
nullptr) mNoteOffCallback(mMessage.channel, mMessage.data1, mMessage.data2);
break;
1303 case NoteOn:
if (mNoteOnCallback !=
nullptr) mNoteOnCallback(mMessage.channel, mMessage.data1, mMessage.data2);
break;
1306 case Clock:
if (mClockCallback !=
nullptr) mClockCallback();
break;
1307 case Start:
if (mStartCallback !=
nullptr) mStartCallback();
break;
1308 case Tick:
if (mTickCallback !=
nullptr) mTickCallback();
break;
1309 case Continue:
if (mContinueCallback !=
nullptr) mContinueCallback();
break;
1310 case Stop:
if (mStopCallback !=
nullptr) mStopCallback();
break;
1311 case ActiveSensing:
if (mActiveSensingCallback !=
nullptr) mActiveSensingCallback();
break;
1314 case ControlChange:
if (mControlChangeCallback !=
nullptr) mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2);
break;
1315 case PitchBend:
if (mPitchBendCallback !=
nullptr) mPitchBendCallback(mMessage.channel, (
int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) +
MIDI_PITCHBEND_MIN);
break;
1316 case AfterTouchPoly:
if (mAfterTouchPolyCallback !=
nullptr) mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2);
break;
1317 case AfterTouchChannel:
if (mAfterTouchChannelCallback !=
nullptr) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1);
break;
1319 case ProgramChange:
if (mProgramChangeCallback !=
nullptr) mProgramChangeCallback(mMessage.channel, mMessage.data1);
break;
1320 case SystemExclusive:
if (mSystemExclusiveCallback !=
nullptr) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize());
break;
1323 case TimeCodeQuarterFrame:
if (mTimeCodeQuarterFrameCallback !=
nullptr) mTimeCodeQuarterFrameCallback(mMessage.data1);
break;
1324 case SongPosition:
if (mSongPositionCallback !=
nullptr) mSongPositionCallback(
unsigned((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)));
break;
1325 case SongSelect:
if (mSongSelectCallback !=
nullptr) mSongSelectCallback(mMessage.data1);
break;
1326 case TuneRequest:
if (mTuneRequestCallback !=
nullptr) mTuneRequestCallback();
break;
1328 case SystemReset:
if (mSystemResetCallback !=
nullptr) mSystemResetCallback();
break;
1351 template<
class Transport,
class Settings,
class Platform>
1354 mThruFilterMode = inThruFilterMode;
1355 mThruActivated = mThruFilterMode !=
Thru::Off;
1358 template<
class Transport,
class Settings,
class Platform>
1361 return mThruFilterMode;
1364 template<
class Transport,
class Settings,
class Platform>
1367 return mThruActivated;
1370 template<
class Transport,
class Settings,
class Platform>
1373 mThruActivated =
true;
1374 mThruFilterMode = inThruFilterMode;
1377 template<
class Transport,
class Settings,
class Platform>
1380 mThruActivated =
false;
1384 template<
class Transport,
class Settings,
class Platform>
1387 if (Settings::UseSenderActiveSensing && mSenderActiveSensingPeriodicity)
1388 mLastMessageSentTime = Platform::now();
1399 template<
class Transport,
class Settings,
class Platform>
1403 if (!mThruActivated || (mThruFilterMode ==
Thru::Off))
1409 const bool filter_condition = ((mMessage.channel == inChannel) ||
1413 switch (mThruFilterMode)
1423 if (filter_condition)
1433 if (!filter_condition)
1449 switch (mMessage.type)
1459 sendRealTime(mMessage.type);
1464 sendSysEx(getSysExArrayLength(), getSysExArray(),
true);
1468 sendSongSelect(mMessage.data1);
1472 sendSongPosition(mMessage.data1 | ((
unsigned)mMessage.data2 << 7));
1476 sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);