diff --git a/.gitignore b/.gitignore index 7491451..87dcd22 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ .vscode/.cmaketools.json src/.DS_Store examples/.DS_Store +.DS_Store diff --git a/src/MIDI.h b/src/MIDI.h index e00bf98..78ba06c 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -86,6 +86,8 @@ public: DataByte inPressure, Channel inChannel); + inline void sendActiveSensing(); + inline void sendSysEx(unsigned inLength, const byte* inArray, bool inArrayContainsBoundaries = false); @@ -241,7 +243,8 @@ private: bool mThruActivated : 1; Thru::Mode mThruFilterMode : 7; MidiMessage mMessage; - + unsigned long mLastSendMessageTime; + bool mActiveSensingActivated; private: inline StatusByte getStatus(MidiType inType, diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7df1afb..0f1aea1 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -40,6 +40,8 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) , mPendingMessageIndex(0) , mCurrentRpnNumber(0xffff) , mCurrentNrpnNumber(0xffff) + , mActiveSensingActivated(false) + , mLastSendMessageTime(0) , mThruActivated(true) , mThruFilterMode(Thru::Full) { @@ -100,6 +102,9 @@ void MidiInterface::begin(Channel inChannel) mCurrentRpnNumber = 0xffff; mCurrentNrpnNumber = 0xffff; + mActiveSensingActivated = false; + mLastSendMessageTime = millis(); + mMessage.valid = false; mMessage.type = InvalidType; mMessage.channel = 0; @@ -177,6 +182,9 @@ void MidiInterface::send(MidiType inType, { sendRealTime(inType); // System Real-time and 1 byte. } + + if (mActiveSensingActivated) + mLastSendMessageTime = millis(); } // ----------------------------------------------------------------------------- @@ -312,6 +320,22 @@ void MidiInterface::sendPitchBend(double inPitchValue, sendPitchBend(value, inChannel); } +/*! \brief Send an Active Sensing message. + + This message is intended to be sent + repeatedly to tell the receiver that a connection is alive. Use + of this message is optional. When initially received, the + receiver will expect to receive another Active Sensing + message each 300ms (max), and if it does not then it will + assume that the connection has been terminated. + */ +template +void MidiInterface::sendActiveSensing() +{ + sendRealTime(ActiveSensing); +} + + /*! \brief Generate and send a System Exclusive frame. \param inLength The size of the array to send \param inArray The byte array containing the data to send @@ -650,6 +674,20 @@ inline bool MidiInterface::read() template inline bool MidiInterface::read(Channel inChannel) { + // Active Sensing. This message is intended to be sent + // repeatedly to tell the receiver that a connection is alive. Use + // of this message is optional. When initially received, the + // receiver will expect to receive another Active Sensing + // message each 300ms (max), and if it does not then it will + // assume that the connection has been terminated. At + // termination, the receiver will turn off all voices and return to + // normal (non- active sensing) operation. + if (mActiveSensingActivated && (millis() - mLastSendMessageTime) > 250) + { + sendActiveSensing(); + mLastSendMessageTime = millis(); + } + if (inChannel >= MIDI_CHANNEL_OFF) return false; // MIDI Input disabled.