From 28d014e68b072018b311683b7d5ed76202d8c5f7 Mon Sep 17 00:00:00 2001 From: Darin Kadrioski Date: Tue, 15 Aug 2017 12:39:08 -0700 Subject: [PATCH 1/4] A total hack, but this allows for continuous streaming of large SysEx messages --- src/MIDI.h | 1 + src/MIDI.hpp | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index 5fe356c1..f3dc6696 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -241,6 +241,7 @@ class MidiInterface bool mThruActivated : 1; Thru::Mode mThruFilterMode : 7; MidiMessage mMessage; + bool mInSystemExclusiveBlock : 1; private: diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 9951261d..eb5e3333 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -42,6 +42,7 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) , mCurrentNrpnNumber(0xffff) , mThruActivated(true) , mThruFilterMode(Thru::Full) + , mInSystemExclusiveBlock(false) { mNoteOffCallback = 0; mNoteOnCallback = 0; @@ -703,7 +704,7 @@ bool MidiInterface::parse() } } - if (mPendingMessageIndex == 0) + if (mPendingMessageIndex == 0 && !mInSystemExclusiveBlock) { // Start a new pending message mPendingMessage[0] = extracted; @@ -775,6 +776,7 @@ bool MidiInterface::parse() mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize; mRunningStatus_RX = InvalidType; mMessage.sysexArray[0] = SystemExclusive; + mInSystemExclusiveBlock = true; break; case InvalidType: @@ -848,17 +850,21 @@ bool MidiInterface::parse() // End of Exclusive case 0xf7: - if (mMessage.sysexArray[0] == SystemExclusive) + if (mMessage.sysexArray[0] == SystemExclusive || mInSystemExclusiveBlock) { // Store the last byte (EOX) mMessage.sysexArray[mPendingMessageIndex++] = 0xf7; mMessage.type = SystemExclusive; + if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) { + mSystemExclusiveCallback(mMessage.sysexArray, mPendingMessageIndex); + } // Get length mMessage.data1 = mPendingMessageIndex & 0xff; // LSB mMessage.data2 = mPendingMessageIndex >> 8; // MSB mMessage.channel = 0; mMessage.valid = true; + mInSystemExclusiveBlock = false; resetInput(); return true; @@ -876,7 +882,7 @@ bool MidiInterface::parse() } // Add extracted data byte to pending message - if (mPendingMessage[0] == SystemExclusive) + if (mPendingMessage[0] == SystemExclusive || mInSystemExclusiveBlock) mMessage.sysexArray[mPendingMessageIndex] = extracted; else mPendingMessage[mPendingMessageIndex] = extracted; @@ -887,9 +893,13 @@ bool MidiInterface::parse() // "FML" case: fall down here with an overflown SysEx.. // This means we received the last possible data byte that can fit // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize. - if (mPendingMessage[0] == SystemExclusive) + if (mPendingMessage[0] == SystemExclusive || mInSystemExclusiveBlock) { - resetInput(); + if (mSystemExclusiveCallback != 0){ + mSystemExclusiveCallback(mMessage.sysexArray, MidiMessage::sSysExMaxSize); + } + + mPendingMessageIndex = 0; return false; } @@ -1217,7 +1227,11 @@ void MidiInterface::launchCallback() case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break; case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break; - case SystemExclusive: if (mSystemExclusiveCallback != 0) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); break; + case SystemExclusive: + if (mSystemExclusiveCallback != 0){ + mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); + } + break; // Occasional messages case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break; @@ -1227,8 +1241,11 @@ void MidiInterface::launchCallback() case SystemReset: if (mSystemResetCallback != 0) mSystemResetCallback(); break; - case InvalidType: + case InvalidType: break; default: + if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) { + mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); + } break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. } } From a9e8e0223710edc73a35aa53b40662282c3b3702 Mon Sep 17 00:00:00 2001 From: Darin Kadrioski Date: Fri, 10 Nov 2017 14:12:00 -0800 Subject: [PATCH 2/4] Adding an injectMessageByteCallback. This allows us to inject arbitrary data into the top of the MIDI stream. --- src/MIDI.h | 2 ++ src/MIDI.hpp | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index f3dc6696..3aca2b02 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -178,6 +178,7 @@ class MidiInterface inline void setHandleStop(void (*fptr)(void)); inline void setHandleActiveSensing(void (*fptr)(void)); inline void setHandleSystemReset(void (*fptr)(void)); + inline void setHandleInjectMessageByte(byte (*fptr)(void)); inline void disconnectCallbackFromType(MidiType inType); @@ -202,6 +203,7 @@ class MidiInterface void (*mStopCallback)(void); void (*mActiveSensingCallback)(void); void (*mSystemResetCallback)(void); + byte (*mInjectMessageByteCallback)(void); // ------------------------------------------------------------------------- // MIDI Soft Thru diff --git a/src/MIDI.hpp b/src/MIDI.hpp index eb5e3333..a7dc8835 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -62,6 +62,7 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) mStopCallback = 0; mActiveSensingCallback = 0; mSystemResetCallback = 0; + mInjectMessageByteCallback = 0; } /*! \brief Destructor for MidiInterface. @@ -676,9 +677,20 @@ inline bool MidiInterface::read(Channel inChannel) template bool MidiInterface::parse() { - if (mSerial.available() == 0) - // No data available. + byte extracted = 255; + + if (mInjectMessageByteCallback != 0) { + extracted = mInjectMessageByteCallback(); + // extracted will remain 255 if no data is enqueued + } + + if (extracted == 255 && mSerial.available() != 0) { + extracted = mSerial.read(); + + } else if (extracted == 255) { + // No data available and no callback. return false; + } // Parsing algorithm: // Get a byte from the serial buffer. @@ -689,8 +701,6 @@ bool MidiInterface::parse() // Else, add the extracted byte to the pending message, and check validity. // When the message is done, store it. - const byte extracted = mSerial.read(); - // Ignore Undefined if (extracted == 0xf9 || extracted == 0xfd) { @@ -1165,6 +1175,7 @@ template void MidiInterface void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } +template void MidiInterface::setHandleInjectMessageByte(byte (*fptr)(void)) { mInjectMessageByteCallback = fptr; } /*! \brief Detach an external function from the given type. From 82954cb6497ed61a4bd4fd27741e71125ba6e22e Mon Sep 17 00:00:00 2001 From: Darin Kadrioski Date: Sat, 11 Nov 2017 21:30:44 -0800 Subject: [PATCH 3/4] Revert "Adding an injectMessageByteCallback. This allows us to inject arbitrary data into the top of the MIDI stream." This reverts commit a9e8e0223710edc73a35aa53b40662282c3b3702. --- src/MIDI.h | 2 -- src/MIDI.hpp | 19 ++++--------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index 3aca2b02..f3dc6696 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -178,7 +178,6 @@ class MidiInterface inline void setHandleStop(void (*fptr)(void)); inline void setHandleActiveSensing(void (*fptr)(void)); inline void setHandleSystemReset(void (*fptr)(void)); - inline void setHandleInjectMessageByte(byte (*fptr)(void)); inline void disconnectCallbackFromType(MidiType inType); @@ -203,7 +202,6 @@ class MidiInterface void (*mStopCallback)(void); void (*mActiveSensingCallback)(void); void (*mSystemResetCallback)(void); - byte (*mInjectMessageByteCallback)(void); // ------------------------------------------------------------------------- // MIDI Soft Thru diff --git a/src/MIDI.hpp b/src/MIDI.hpp index a7dc8835..eb5e3333 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -62,7 +62,6 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) mStopCallback = 0; mActiveSensingCallback = 0; mSystemResetCallback = 0; - mInjectMessageByteCallback = 0; } /*! \brief Destructor for MidiInterface. @@ -677,20 +676,9 @@ inline bool MidiInterface::read(Channel inChannel) template bool MidiInterface::parse() { - byte extracted = 255; - - if (mInjectMessageByteCallback != 0) { - extracted = mInjectMessageByteCallback(); - // extracted will remain 255 if no data is enqueued - } - - if (extracted == 255 && mSerial.available() != 0) { - extracted = mSerial.read(); - - } else if (extracted == 255) { - // No data available and no callback. + if (mSerial.available() == 0) + // No data available. return false; - } // Parsing algorithm: // Get a byte from the serial buffer. @@ -701,6 +689,8 @@ bool MidiInterface::parse() // Else, add the extracted byte to the pending message, and check validity. // When the message is done, store it. + const byte extracted = mSerial.read(); + // Ignore Undefined if (extracted == 0xf9 || extracted == 0xfd) { @@ -1175,7 +1165,6 @@ template void MidiInterface void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } -template void MidiInterface::setHandleInjectMessageByte(byte (*fptr)(void)) { mInjectMessageByteCallback = fptr; } /*! \brief Detach an external function from the given type. From 921bb20fc6e6f880205b4bf3693cc5fc3475f77c Mon Sep 17 00:00:00 2001 From: Darin Kadrioski Date: Tue, 17 Sep 2024 18:25:34 -0700 Subject: [PATCH 4/4] formatting --- src/MIDI.hpp | 831 ++++++++++++++++++++++++++++----------------------- 1 file changed, 465 insertions(+), 366 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index eb5e3333..5623b22c 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -30,45 +30,35 @@ BEGIN_MIDI_NAMESPACE /// \brief Constructor for MidiInterface. -template -inline MidiInterface::MidiInterface(SerialPort& inSerial) - : mSerial(inSerial) - , mInputChannel(0) - , mRunningStatus_RX(InvalidType) - , mRunningStatus_TX(InvalidType) - , mPendingMessageExpectedLenght(0) - , mPendingMessageIndex(0) - , mCurrentRpnNumber(0xffff) - , mCurrentNrpnNumber(0xffff) - , mThruActivated(true) - , mThruFilterMode(Thru::Full) - , mInSystemExclusiveBlock(false) +template +inline MidiInterface::MidiInterface(SerialPort &inSerial) + : mSerial(inSerial), mInputChannel(0), mRunningStatus_RX(InvalidType), mRunningStatus_TX(InvalidType), mPendingMessageExpectedLenght(0), mPendingMessageIndex(0), mCurrentRpnNumber(0xffff), mCurrentNrpnNumber(0xffff), mThruActivated(true), mThruFilterMode(Thru::Full), mInSystemExclusiveBlock(false) { - mNoteOffCallback = 0; - mNoteOnCallback = 0; - mAfterTouchPolyCallback = 0; - mControlChangeCallback = 0; - mProgramChangeCallback = 0; - mAfterTouchChannelCallback = 0; - mPitchBendCallback = 0; - mSystemExclusiveCallback = 0; - mTimeCodeQuarterFrameCallback = 0; - mSongPositionCallback = 0; - mSongSelectCallback = 0; - mTuneRequestCallback = 0; - mClockCallback = 0; - mStartCallback = 0; - mContinueCallback = 0; - mStopCallback = 0; - mActiveSensingCallback = 0; - mSystemResetCallback = 0; + mNoteOffCallback = 0; + mNoteOnCallback = 0; + mAfterTouchPolyCallback = 0; + mControlChangeCallback = 0; + mProgramChangeCallback = 0; + mAfterTouchChannelCallback = 0; + mPitchBendCallback = 0; + mSystemExclusiveCallback = 0; + mTimeCodeQuarterFrameCallback = 0; + mSongPositionCallback = 0; + mSongSelectCallback = 0; + mTuneRequestCallback = 0; + mClockCallback = 0; + mStartCallback = 0; + mContinueCallback = 0; + mStopCallback = 0; + mActiveSensingCallback = 0; + mSystemResetCallback = 0; } /*! \brief Destructor for MidiInterface. This is not really useful for the Arduino, as it is never called... */ -template +template inline MidiInterface::~MidiInterface() { } @@ -81,12 +71,12 @@ inline MidiInterface::~MidiInterface() - Input channel set to 1 if no value is specified - Full thru mirroring */ -template +template void MidiInterface::begin(Channel inChannel) { // Initialise the Serial port #if defined(AVR_CAKE) - mSerial. template open(); + mSerial.template open(); #else mSerial.begin(Settings::BaudRate); #endif @@ -98,17 +88,17 @@ void MidiInterface::begin(Channel inChannel) mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; - mCurrentRpnNumber = 0xffff; + mCurrentRpnNumber = 0xffff; mCurrentNrpnNumber = 0xffff; - mMessage.valid = false; - mMessage.type = InvalidType; + mMessage.valid = false; + mMessage.type = InvalidType; mMessage.channel = 0; - mMessage.data1 = 0; - mMessage.data2 = 0; + mMessage.data1 = 0; + mMessage.data2 = 0; mThruFilterMode = Thru::Full; - mThruActivated = true; + mThruActivated = true; } // ----------------------------------------------------------------------------- @@ -130,21 +120,21 @@ void MidiInterface::begin(Channel inChannel) This is an internal method, use it only if you need to send raw data from your code, at your own risks. */ -template +template void MidiInterface::send(MidiType inType, DataByte inData1, DataByte inData2, Channel inChannel) { // Then test if channel is valid - if (inChannel >= MIDI_CHANNEL_OFF || + if (inChannel >= MIDI_CHANNEL_OFF || inChannel == MIDI_CHANNEL_OMNI || inType < 0x80) { return; // Don't send anything } - if (inType <= PitchBend) // Channel messages + if (inType <= PitchBend) // Channel messages { // Protection: remove MSBs on data inData1 &= 0x7f; @@ -191,7 +181,7 @@ void MidiInterface::send(MidiType inType, Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html */ -template +template void MidiInterface::sendNoteOn(DataByte inNoteNumber, DataByte inVelocity, Channel inChannel) @@ -210,7 +200,7 @@ void MidiInterface::sendNoteOn(DataByte inNoteNumber, Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html */ -template +template void MidiInterface::sendNoteOff(DataByte inNoteNumber, DataByte inVelocity, Channel inChannel) @@ -222,7 +212,7 @@ void MidiInterface::sendNoteOff(DataByte inNoteNumber, \param inProgramNumber The Program to select (0 to 127). \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template void MidiInterface::sendProgramChange(DataByte inProgramNumber, Channel inChannel) { @@ -235,7 +225,7 @@ void MidiInterface::sendProgramChange(DataByte inProgramNu \param inChannel The channel on which the message will be sent (1 to 16). @see MidiControlChangeNumber */ -template +template void MidiInterface::sendControlChange(DataByte inControlNumber, DataByte inControlValue, Channel inChannel) @@ -250,7 +240,7 @@ void MidiInterface::sendControlChange(DataByte inControlNu Note: this method is deprecated and will be removed in a future revision of the library, @see sendAfterTouch to send polyphonic and monophonic AfterTouch messages. */ -template +template void MidiInterface::sendPolyPressure(DataByte inNoteNumber, DataByte inPressure, Channel inChannel) @@ -262,7 +252,7 @@ void MidiInterface::sendPolyPressure(DataByte inNoteNumber \param inPressure The amount of AfterTouch to apply to all notes. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template void MidiInterface::sendAfterTouch(DataByte inPressure, Channel inChannel) { @@ -275,7 +265,7 @@ void MidiInterface::sendAfterTouch(DataByte inPressure, \param inChannel The channel on which the message will be sent (1 to 16). @see Replaces sendPolyPressure (which is now deprecated). */ -template +template void MidiInterface::sendAfterTouch(DataByte inNoteNumber, DataByte inPressure, Channel inChannel) @@ -289,7 +279,7 @@ void MidiInterface::sendAfterTouch(DataByte inNoteNumber, center value is 0. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template void MidiInterface::sendPitchBend(int inPitchValue, Channel inChannel) { @@ -297,14 +287,13 @@ void MidiInterface::sendPitchBend(int inPitchValue, send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel); } - /*! \brief Send a Pitch Bend message using a floating point value. \param inPitchValue The amount of bend to send (in a floating point format), between -1.0f (maximum downwards bend) and +1.0f (max upwards bend), center value is 0.0f. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template void MidiInterface::sendPitchBend(double inPitchValue, Channel inChannel) { @@ -322,9 +311,9 @@ void MidiInterface::sendPitchBend(double inPitchValue, default value for ArrayContainsBoundaries is set to 'false' for compatibility with previous versions of the library. */ -template +template void MidiInterface::sendSysEx(unsigned inLength, - const byte* inArray, + const byte *inArray, bool inArrayContainsBoundaries) { const bool writeBeginEndBytes = !inArrayContainsBoundaries; @@ -355,7 +344,7 @@ void MidiInterface::sendSysEx(unsigned inLength, When a MIDI unit receives this message, it should tune its oscillators (if equipped with any). */ -template +template void MidiInterface::sendTuneRequest() { mSerial.write(TuneRequest); @@ -372,7 +361,7 @@ void MidiInterface::sendTuneRequest() \param inValuesNibble MTC data See MIDI Specification for more information. */ -template +template void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, DataByte inValuesNibble) { @@ -386,7 +375,7 @@ void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTy \param inData if you want to encode directly the nibbles in your program, you can send the byte here. */ -template +template void MidiInterface::sendTimeCodeQuarterFrame(DataByte inData) { mSerial.write((byte)TimeCodeQuarterFrame); @@ -401,7 +390,7 @@ void MidiInterface::sendTimeCodeQuarterFrame(DataByte inDa /*! \brief Send a Song Position Pointer message. \param inBeats The number of beats since the start of the song. */ -template +template void MidiInterface::sendSongPosition(unsigned inBeats) { mSerial.write((byte)SongPosition); @@ -415,7 +404,7 @@ void MidiInterface::sendSongPosition(unsigned inBeats) } /*! \brief Send a Song Select message */ -template +template void MidiInterface::sendSongSelect(DataByte inSongNumber) { mSerial.write((byte)SongSelect); @@ -433,7 +422,7 @@ void MidiInterface::sendSongSelect(DataByte inSongNumber) Start, Stop, Continue, Clock, ActiveSensing and SystemReset. @see MidiType */ -template +template void MidiInterface::sendRealTime(MidiType inType) { // Do not invalidate Running Status for real-time messages @@ -441,17 +430,17 @@ void MidiInterface::sendRealTime(MidiType inType) switch (inType) { - case Clock: - case Start: - case Stop: - case Continue: - case ActiveSensing: - case SystemReset: - mSerial.write((byte)inType); - break; - default: - // Invalid Real Time marker - break; + case Clock: + case Start: + case Stop: + case Continue: + case ActiveSensing: + case SystemReset: + mSerial.write((byte)inType); + break; + default: + // Invalid Real Time marker + break; } } @@ -459,7 +448,7 @@ void MidiInterface::sendRealTime(MidiType inType) \param inNumber The 14-bit number of the RPN you want to select. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::beginRpn(unsigned inNumber, Channel inChannel) { @@ -477,10 +466,11 @@ inline void MidiInterface::beginRpn(unsigned inNumber, \param inValue The 14-bit value of the selected RPN. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::sendRpnValue(unsigned inValue, Channel inChannel) -{; +{ + ; const byte valMsb = 0x7f & (inValue >> 7); const byte valLsb = 0x7f & inValue; sendControlChange(DataEntryMSB, valMsb, inChannel); @@ -492,7 +482,7 @@ inline void MidiInterface::sendRpnValue(unsigned inValue, \param inLsb The LSB part of the value to send. Meaning depends on RPN number. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::sendRpnValue(byte inMsb, byte inLsb, Channel inChannel) @@ -504,7 +494,7 @@ inline void MidiInterface::sendRpnValue(byte inMsb, /* \brief Increment the value of the currently selected RPN number by the specified amount. \param inAmount The amount to add to the currently selected RPN value. */ -template +template inline void MidiInterface::sendRpnIncrement(byte inAmount, Channel inChannel) { @@ -514,7 +504,7 @@ inline void MidiInterface::sendRpnIncrement(byte inAmount, /* \brief Decrement the value of the currently selected RPN number by the specified amount. \param inAmount The amount to subtract to the currently selected RPN value. */ -template +template inline void MidiInterface::sendRpnDecrement(byte inAmount, Channel inChannel) { @@ -525,7 +515,7 @@ inline void MidiInterface::sendRpnDecrement(byte inAmount, This will send a Null Function to deselect the currently selected RPN. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::endRpn(Channel inChannel) { sendControlChange(RPNLSB, 0x7f, inChannel); @@ -533,13 +523,11 @@ inline void MidiInterface::endRpn(Channel inChannel) mCurrentRpnNumber = 0xffff; } - - /*! \brief Start a Non-Registered Parameter Number frame. \param inNumber The 14-bit number of the NRPN you want to select. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::beginNrpn(unsigned inNumber, Channel inChannel) { @@ -557,10 +545,11 @@ inline void MidiInterface::beginNrpn(unsigned inNumber, \param inValue The 14-bit value of the selected NRPN. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::sendNrpnValue(unsigned inValue, Channel inChannel) -{; +{ + ; const byte valMsb = 0x7f & (inValue >> 7); const byte valLsb = 0x7f & inValue; sendControlChange(DataEntryMSB, valMsb, inChannel); @@ -572,7 +561,7 @@ inline void MidiInterface::sendNrpnValue(unsigned inValue, \param inLsb The LSB part of the value to send. Meaning depends on NRPN number. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::sendNrpnValue(byte inMsb, byte inLsb, Channel inChannel) @@ -584,7 +573,7 @@ inline void MidiInterface::sendNrpnValue(byte inMsb, /* \brief Increment the value of the currently selected NRPN number by the specified amount. \param inAmount The amount to add to the currently selected NRPN value. */ -template +template inline void MidiInterface::sendNrpnIncrement(byte inAmount, Channel inChannel) { @@ -594,7 +583,7 @@ inline void MidiInterface::sendNrpnIncrement(byte inAmount /* \brief Decrement the value of the currently selected NRPN number by the specified amount. \param inAmount The amount to subtract to the currently selected NRPN value. */ -template +template inline void MidiInterface::sendNrpnDecrement(byte inAmount, Channel inChannel) { @@ -605,7 +594,7 @@ inline void MidiInterface::sendNrpnDecrement(byte inAmount This will send a Null Function to deselect the currently selected NRPN. \param inChannel The channel on which the message will be sent (1 to 16). */ -template +template inline void MidiInterface::endNrpn(Channel inChannel) { sendControlChange(NRPNLSB, 0x7f, inChannel); @@ -617,7 +606,7 @@ inline void MidiInterface::endNrpn(Channel inChannel) // ----------------------------------------------------------------------------- -template +template StatusByte MidiInterface::getStatus(MidiType inType, Channel inChannel) const { @@ -640,7 +629,7 @@ StatusByte MidiInterface::getStatus(MidiType inType, it is sent back on the MIDI output. @see see setInputChannel() */ -template +template inline bool MidiInterface::read() { return read(mInputChannel); @@ -648,7 +637,7 @@ inline bool MidiInterface::read() /*! \brief Read messages on a specified channel. */ -template +template inline bool MidiInterface::read(Channel inChannel) { if (inChannel >= MIDI_CHANNEL_OFF) @@ -662,7 +651,7 @@ inline bool MidiInterface::read(Channel inChannel) if (channelMatch) { - launchCallback(); + // launchCallback(); } thruFilter(inChannel); @@ -673,7 +662,7 @@ inline bool MidiInterface::read(Channel inChannel) // ----------------------------------------------------------------------------- // Private method: MIDI parser -template +template bool MidiInterface::parse() { if (mSerial.available() == 0) @@ -718,8 +707,8 @@ bool MidiInterface::parse() // to the pending message if (extracted < 0x80) { - mPendingMessage[0] = mRunningStatus_RX; - mPendingMessage[1] = extracted; + mPendingMessage[0] = mRunningStatus_RX; + mPendingMessage[1] = extracted; mPendingMessageIndex = 1; } // Else: well, we received another status byte, @@ -729,71 +718,71 @@ bool MidiInterface::parse() switch (getTypeFromStatusByte(mPendingMessage[0])) { - // 1 byte messages - case Start: - case Continue: - case Stop: - case Clock: - case ActiveSensing: - case SystemReset: - case TuneRequest: - // Handle the message type directly here. - mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); - mMessage.channel = 0; - mMessage.data1 = 0; - mMessage.data2 = 0; - mMessage.valid = true; + // 1 byte messages + case Start: + case Continue: + case Stop: + case Clock: + case ActiveSensing: + case SystemReset: + case TuneRequest: + // Handle the message type directly here. + mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); + mMessage.channel = 0; + mMessage.data1 = 0; + mMessage.data2 = 0; + mMessage.valid = true; - // Do not reset all input attributes, Running Status must remain unchanged. - // We still need to reset these - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; + // Do not reset all input attributes, Running Status must remain unchanged. + // We still need to reset these + mPendingMessageIndex = 0; + mPendingMessageExpectedLenght = 0; - return true; - break; + return true; + break; - // 2 bytes messages - case ProgramChange: - case AfterTouchChannel: - case TimeCodeQuarterFrame: - case SongSelect: - mPendingMessageExpectedLenght = 2; - break; + // 2 bytes messages + case ProgramChange: + case AfterTouchChannel: + case TimeCodeQuarterFrame: + case SongSelect: + mPendingMessageExpectedLenght = 2; + break; - // 3 bytes messages - case NoteOn: - case NoteOff: - case ControlChange: - case PitchBend: - case AfterTouchPoly: - case SongPosition: - mPendingMessageExpectedLenght = 3; - break; + // 3 bytes messages + case NoteOn: + case NoteOff: + case ControlChange: + case PitchBend: + case AfterTouchPoly: + case SongPosition: + mPendingMessageExpectedLenght = 3; + break; - case SystemExclusive: - // The message can be any lenght - // between 3 and MidiMessage::sSysExMaxSize bytes - mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize; - mRunningStatus_RX = InvalidType; - mMessage.sysexArray[0] = SystemExclusive; - mInSystemExclusiveBlock = true; - break; + case SystemExclusive: + // The message can be any lenght + // between 3 and MidiMessage::sSysExMaxSize bytes + mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize; + mRunningStatus_RX = InvalidType; + mMessage.sysexArray[0] = SystemExclusive; + mInSystemExclusiveBlock = true; + break; - case InvalidType: - default: - // This is obviously wrong. Let's get the hell out'a here. - resetInput(); - return false; - break; + case InvalidType: + default: + // This is obviously wrong. Let's get the hell out'a here. + resetInput(); + return false; + break; } if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) { // Reception complete - mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); + mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); - mMessage.data1 = mPendingMessage[1]; - mMessage.data2 = 0; // Completed new message has 1 data byte + mMessage.data1 = mPendingMessage[1]; + mMessage.data2 = 0; // Completed new message has 1 data byte mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; @@ -827,57 +816,58 @@ bool MidiInterface::parse() // are allowed only for interleaved Real Time message or EOX switch (extracted) { - case Clock: - case Start: - case Continue: - case Stop: - case ActiveSensing: - case SystemReset: - - // Here we will have to extract the one-byte message, - // pass it to the structure for being read outside - // the MIDI class, and recompose the message it was - // interleaved into. Oh, and without killing the running status.. - // This is done by leaving the pending message as is, - // it will be completed on next calls. - - mMessage.type = (MidiType)extracted; - mMessage.data1 = 0; - mMessage.data2 = 0; - mMessage.channel = 0; - mMessage.valid = true; - return true; + case Clock: + case Start: + case Continue: + case Stop: + case ActiveSensing: + case SystemReset: - // End of Exclusive - case 0xf7: - if (mMessage.sysexArray[0] == SystemExclusive || mInSystemExclusiveBlock) - { - // Store the last byte (EOX) - mMessage.sysexArray[mPendingMessageIndex++] = 0xf7; - mMessage.type = SystemExclusive; - - if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) { - mSystemExclusiveCallback(mMessage.sysexArray, mPendingMessageIndex); - } - // Get length - mMessage.data1 = mPendingMessageIndex & 0xff; // LSB - mMessage.data2 = mPendingMessageIndex >> 8; // MSB - mMessage.channel = 0; - mMessage.valid = true; - mInSystemExclusiveBlock = false; - - resetInput(); - return true; - } - else + // Here we will have to extract the one-byte message, + // pass it to the structure for being read outside + // the MIDI class, and recompose the message it was + // interleaved into. Oh, and without killing the running status.. + // This is done by leaving the pending message as is, + // it will be completed on next calls. + + mMessage.type = (MidiType)extracted; + mMessage.data1 = 0; + mMessage.data2 = 0; + mMessage.channel = 0; + mMessage.valid = true; + return true; + + // End of Exclusive + case 0xf7: + if (mMessage.sysexArray[0] == SystemExclusive || mInSystemExclusiveBlock) + { + // Store the last byte (EOX) + mMessage.sysexArray[mPendingMessageIndex++] = 0xf7; + mMessage.type = SystemExclusive; + + if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) { - // Well well well.. error. - resetInput(); - return false; + mSystemExclusiveCallback(mMessage.sysexArray, mPendingMessageIndex); } + // Get length + mMessage.data1 = mPendingMessageIndex & 0xff; // LSB + mMessage.data2 = mPendingMessageIndex >> 8; // MSB + mMessage.channel = 0; + mMessage.valid = true; + mInSystemExclusiveBlock = false; - default: - break; // LCOV_EXCL_LINE - Coverage blind spot + resetInput(); + return true; + } + else + { + // Well well well.. error. + resetInput(); + return false; + } + + default: + break; // LCOV_EXCL_LINE - Coverage blind spot } } @@ -895,8 +885,9 @@ bool MidiInterface::parse() // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize. if (mPendingMessage[0] == SystemExclusive || mInSystemExclusiveBlock) { - if (mSystemExclusiveCallback != 0){ - mSystemExclusiveCallback(mMessage.sysexArray, MidiMessage::sSysExMaxSize); + if (mSystemExclusiveCallback != 0) + { + mSystemExclusiveCallback(mMessage.sysexArray, MidiMessage::sSysExMaxSize); } mPendingMessageIndex = 0; @@ -924,21 +915,21 @@ bool MidiInterface::parse() // Activate running status (if enabled for the received type) switch (mMessage.type) { - case NoteOff: - case NoteOn: - case AfterTouchPoly: - case ControlChange: - case ProgramChange: - case AfterTouchChannel: - case PitchBend: - // Running status enabled: store it from received message - mRunningStatus_RX = mPendingMessage[0]; - break; - - default: - // No running status - mRunningStatus_RX = InvalidType; - break; + case NoteOff: + case NoteOn: + case AfterTouchPoly: + case ControlChange: + case ProgramChange: + case AfterTouchChannel: + case PitchBend: + // Running status enabled: store it from received message + mRunningStatus_RX = mPendingMessage[0]; + break; + + default: + // No running status + mRunningStatus_RX = InvalidType; + break; } return true; } @@ -962,7 +953,7 @@ bool MidiInterface::parse() } // Private method, see midi_Settings.h for documentation -template +template inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() { if (Settings::HandleNullVelocityNoteOnAsNoteOff && @@ -973,7 +964,7 @@ inline void MidiInterface::handleNullVelocityNoteOnAsNoteO } // Private method: check if the received message is on the listened channel -template +template inline bool MidiInterface::inputFilter(Channel inChannel) { // This method handles recognition of channel @@ -1002,7 +993,7 @@ inline bool MidiInterface::inputFilter(Channel inChannel) } // Private method: reset input attributes -template +template inline void MidiInterface::resetInput() { mPendingMessageIndex = 0; @@ -1016,7 +1007,7 @@ inline void MidiInterface::resetInput() Returns an enumerated type. @see MidiType */ -template +template inline MidiType MidiInterface::getType() const { return mMessage.type; @@ -1027,21 +1018,21 @@ inline MidiType MidiInterface::getType() const \return Channel range is 1 to 16. For non-channel messages, this will return 0. */ -template +template inline Channel MidiInterface::getChannel() const { return mMessage.channel; } /*! \brief Get the first data byte of the last received message. */ -template +template inline DataByte MidiInterface::getData1() const { return mMessage.data1; } /*! \brief Get the second data byte of the last received message. */ -template +template inline DataByte MidiInterface::getData2() const { return mMessage.data2; @@ -1051,8 +1042,8 @@ inline DataByte MidiInterface::getData2() const @see getSysExArrayLength to get the array's length in bytes. */ -template -inline const byte* MidiInterface::getSysExArray() const +template +inline const byte *MidiInterface::getSysExArray() const { return mMessage.sysexArray; } @@ -1062,14 +1053,14 @@ inline const byte* MidiInterface::getSysExArray() const It is coded using data1 as LSB and data2 as MSB. \return The array's length, in bytes. */ -template +template inline unsigned MidiInterface::getSysExArrayLength() const { return mMessage.getSysExSize(); } /*! \brief Check if a valid message is stored in the structure. */ -template +template inline bool MidiInterface::check() const { return mMessage.valid; @@ -1077,7 +1068,7 @@ inline bool MidiInterface::check() const // ----------------------------------------------------------------------------- -template +template inline Channel MidiInterface::getInputChannel() const { return mInputChannel; @@ -1087,7 +1078,7 @@ inline Channel MidiInterface::getInputChannel() const \param inChannel the channel value. Valid values are 1 to 16, MIDI_CHANNEL_OMNI if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input. */ -template +template inline void MidiInterface::setInputChannel(Channel inChannel) { mInputChannel = inChannel; @@ -1100,10 +1091,10 @@ inline void MidiInterface::setInputChannel(Channel inChann This is a utility static method, used internally, made public so you can handle MidiTypes more easily. */ -template +template MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) { - if ((inStatus < 0x80) || + if ((inStatus < 0x80) || (inStatus == 0xf4) || (inStatus == 0xf5) || (inStatus == 0xf9) || @@ -1123,21 +1114,21 @@ MidiType MidiInterface::getTypeFromStatusByte(byte inStatu /*! \brief Returns channel in the range 1-16 */ -template +template inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) { return (inStatus & 0x0f) + 1; } -template +template bool MidiInterface::isChannelMessage(MidiType inType) { - return (inType == NoteOff || - inType == NoteOn || - inType == ControlChange || - inType == AfterTouchPoly || + return (inType == NoteOff || + inType == NoteOn || + inType == ControlChange || + inType == AfterTouchPoly || inType == AfterTouchChannel || - inType == PitchBend || + inType == PitchBend || inType == ProgramChange); } @@ -1147,24 +1138,42 @@ bool MidiInterface::isChannelMessage(MidiType inType) @{ */ -template void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } -template void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } -template void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } -template void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } -template void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } -template void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } -template void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } -template void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte* array, unsigned size)) { mSystemExclusiveCallback = fptr; } -template void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } -template void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } -template void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } -template void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } -template void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } -template void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } -template void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } -template void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } -template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } -template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } +template +void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } +template +void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } +template +void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } +template +void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } +template +void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } +template +void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } +template +void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } +template +void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte *array, unsigned size)) { mSystemExclusiveCallback = fptr; } +template +void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } +template +void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } +template +void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } +template +void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } +template +void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } +template +void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } +template +void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } +template +void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } +template +void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } +template +void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } /*! \brief Detach an external function from the given type. @@ -1172,81 +1181,171 @@ template void MidiInterface +template void MidiInterface::disconnectCallbackFromType(MidiType inType) { switch (inType) { - case NoteOff: mNoteOffCallback = 0; break; - case NoteOn: mNoteOnCallback = 0; break; - case AfterTouchPoly: mAfterTouchPolyCallback = 0; break; - case ControlChange: mControlChangeCallback = 0; break; - case ProgramChange: mProgramChangeCallback = 0; break; - case AfterTouchChannel: mAfterTouchChannelCallback = 0; break; - case PitchBend: mPitchBendCallback = 0; break; - case SystemExclusive: mSystemExclusiveCallback = 0; break; - case TimeCodeQuarterFrame: mTimeCodeQuarterFrameCallback = 0; break; - case SongPosition: mSongPositionCallback = 0; break; - case SongSelect: mSongSelectCallback = 0; break; - case TuneRequest: mTuneRequestCallback = 0; break; - case Clock: mClockCallback = 0; break; - case Start: mStartCallback = 0; break; - case Continue: mContinueCallback = 0; break; - case Stop: mStopCallback = 0; break; - case ActiveSensing: mActiveSensingCallback = 0; break; - case SystemReset: mSystemResetCallback = 0; break; - default: - break; + case NoteOff: + mNoteOffCallback = 0; + break; + case NoteOn: + mNoteOnCallback = 0; + break; + case AfterTouchPoly: + mAfterTouchPolyCallback = 0; + break; + case ControlChange: + mControlChangeCallback = 0; + break; + case ProgramChange: + mProgramChangeCallback = 0; + break; + case AfterTouchChannel: + mAfterTouchChannelCallback = 0; + break; + case PitchBend: + mPitchBendCallback = 0; + break; + case SystemExclusive: + mSystemExclusiveCallback = 0; + break; + case TimeCodeQuarterFrame: + mTimeCodeQuarterFrameCallback = 0; + break; + case SongPosition: + mSongPositionCallback = 0; + break; + case SongSelect: + mSongSelectCallback = 0; + break; + case TuneRequest: + mTuneRequestCallback = 0; + break; + case Clock: + mClockCallback = 0; + break; + case Start: + mStartCallback = 0; + break; + case Continue: + mContinueCallback = 0; + break; + case Stop: + mStopCallback = 0; + break; + case ActiveSensing: + mActiveSensingCallback = 0; + break; + case SystemReset: + mSystemResetCallback = 0; + break; + default: + break; } } /*! @} */ // End of doc group MIDI Callbacks // Private - launch callback function based on received type. -template +template void MidiInterface::launchCallback() { // The order is mixed to allow frequent messages to trigger their callback faster. switch (mMessage.type) { - // Notes - case NoteOff: if (mNoteOffCallback != 0) mNoteOffCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case NoteOn: if (mNoteOnCallback != 0) mNoteOnCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - - // Real-time messages - case Clock: if (mClockCallback != 0) mClockCallback(); break; - case Start: if (mStartCallback != 0) mStartCallback(); break; - case Continue: if (mContinueCallback != 0) mContinueCallback(); break; - case Stop: if (mStopCallback != 0) mStopCallback(); break; - case ActiveSensing: if (mActiveSensingCallback != 0) mActiveSensingCallback(); break; - - // Continuous controllers - case ControlChange: if (mControlChangeCallback != 0) mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case PitchBend: if (mPitchBendCallback != 0) mPitchBendCallback(mMessage.channel, (int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN); break; // TODO: check this - case AfterTouchPoly: if (mAfterTouchPolyCallback != 0) mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break; - - case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break; - case SystemExclusive: - if (mSystemExclusiveCallback != 0){ + // Notes + case NoteOff: + if (mNoteOffCallback != 0) + mNoteOffCallback(mMessage.channel, mMessage.data1, mMessage.data2); + break; + case NoteOn: + if (mNoteOnCallback != 0) + mNoteOnCallback(mMessage.channel, mMessage.data1, mMessage.data2); + break; + + // Real-time messages + case Clock: + if (mClockCallback != 0) + mClockCallback(); + break; + case Start: + if (mStartCallback != 0) + mStartCallback(); + break; + case Continue: + if (mContinueCallback != 0) + mContinueCallback(); + break; + case Stop: + if (mStopCallback != 0) + mStopCallback(); + break; + case ActiveSensing: + if (mActiveSensingCallback != 0) + mActiveSensingCallback(); + break; + + // Continuous controllers + case ControlChange: + if (mControlChangeCallback != 0) + mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2); + break; + case PitchBend: + if (mPitchBendCallback != 0) + mPitchBendCallback(mMessage.channel, (int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN); + break; // TODO: check this + case AfterTouchPoly: + if (mAfterTouchPolyCallback != 0) + mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2); + break; + case AfterTouchChannel: + if (mAfterTouchChannelCallback != 0) + mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); + break; + + case ProgramChange: + if (mProgramChangeCallback != 0) + mProgramChangeCallback(mMessage.channel, mMessage.data1); + break; + case SystemExclusive: + if (mSystemExclusiveCallback != 0) + { mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); - } - break; - - // Occasional messages - case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break; - case SongPosition: if (mSongPositionCallback != 0) mSongPositionCallback((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)); break; - case SongSelect: if (mSongSelectCallback != 0) mSongSelectCallback(mMessage.data1); break; - case TuneRequest: if (mTuneRequestCallback != 0) mTuneRequestCallback(); break; - - case SystemReset: if (mSystemResetCallback != 0) mSystemResetCallback(); break; - - case InvalidType: break; - default: - if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) { - mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); - } - break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. + } + break; + + // Occasional messages + case TimeCodeQuarterFrame: + if (mTimeCodeQuarterFrameCallback != 0) + mTimeCodeQuarterFrameCallback(mMessage.data1); + break; + case SongPosition: + if (mSongPositionCallback != 0) + mSongPositionCallback((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)); + break; + case SongSelect: + if (mSongSelectCallback != 0) + mSongSelectCallback(mMessage.data1); + break; + case TuneRequest: + if (mTuneRequestCallback != 0) + mTuneRequestCallback(); + break; + + case SystemReset: + if (mSystemResetCallback != 0) + mSystemResetCallback(); + break; + + case InvalidType: + break; + default: + if (mInSystemExclusiveBlock && mSystemExclusiveCallback != 0) + { + mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); + } + break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. } } @@ -1265,33 +1364,33 @@ void MidiInterface::launchCallback() @see Thru::Mode */ -template +template inline void MidiInterface::setThruFilterMode(Thru::Mode inThruFilterMode) { mThruFilterMode = inThruFilterMode; - mThruActivated = mThruFilterMode != Thru::Off; + mThruActivated = mThruFilterMode != Thru::Off; } -template +template inline Thru::Mode MidiInterface::getFilterMode() const { return mThruFilterMode; } -template +template inline bool MidiInterface::getThruState() const { return mThruActivated; } -template +template inline void MidiInterface::turnThruOn(Thru::Mode inThruFilterMode) { mThruActivated = true; mThruFilterMode = inThruFilterMode; } -template +template inline void MidiInterface::turnThruOff() { mThruActivated = false; @@ -1306,7 +1405,7 @@ inline void MidiInterface::turnThruOff() // to output unless filter is set to Off. // - Channel messages are passed to the output whether their channel // is matching the input channel and the filter setting -template +template void MidiInterface::thruFilter(Channel inChannel) { // If the feature is disabled, don't do anything. @@ -1322,35 +1421,35 @@ void MidiInterface::thruFilter(Channel inChannel) // Now let's pass it to the output switch (mThruFilterMode) { - case Thru::Full: + case Thru::Full: + send(mMessage.type, + mMessage.data1, + mMessage.data2, + mMessage.channel); + break; + + case Thru::SameChannel: + if (filter_condition) + { send(mMessage.type, mMessage.data1, mMessage.data2, mMessage.channel); - break; - - case Thru::SameChannel: - if (filter_condition) - { - send(mMessage.type, - mMessage.data1, - mMessage.data2, - mMessage.channel); - } - break; + } + break; - case Thru::DifferentChannel: - if (!filter_condition) - { - send(mMessage.type, - mMessage.data1, - mMessage.data2, - mMessage.channel); - } - break; + case Thru::DifferentChannel: + if (!filter_condition) + { + send(mMessage.type, + mMessage.data1, + mMessage.data2, + mMessage.channel); + } + break; - default: - break; + default: + break; } } else @@ -1358,36 +1457,36 @@ void MidiInterface::thruFilter(Channel inChannel) // Send the message to the output switch (mMessage.type) { - // Real Time and 1 byte - case Clock: - case Start: - case Stop: - case Continue: - case ActiveSensing: - case SystemReset: - case TuneRequest: - sendRealTime(mMessage.type); - break; + // Real Time and 1 byte + case Clock: + case Start: + case Stop: + case Continue: + case ActiveSensing: + case SystemReset: + case TuneRequest: + sendRealTime(mMessage.type); + break; - case SystemExclusive: - // Send SysEx (0xf0 and 0xf7 are included in the buffer) - sendSysEx(getSysExArrayLength(), getSysExArray(), true); - break; + case SystemExclusive: + // Send SysEx (0xf0 and 0xf7 are included in the buffer) + sendSysEx(getSysExArrayLength(), getSysExArray(), true); + break; - case SongSelect: - sendSongSelect(mMessage.data1); - break; + case SongSelect: + sendSongSelect(mMessage.data1); + break; - case SongPosition: - sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7)); - break; + case SongPosition: + sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7)); + break; - case TimeCodeQuarterFrame: - sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2); - break; + case TimeCodeQuarterFrame: + sendTimeCodeQuarterFrame(mMessage.data1, mMessage.data2); + break; - default: - break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. + default: + break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. } } }