Working on thru.
This commit is contained in:
parent
d8e0631399
commit
8c9d289216
31
src/MIDI.h
31
src/MIDI.h
|
|
@ -68,7 +68,7 @@ public:
|
|||
inline void sendAfterTouch(DataByte inPressure,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendSysEx(unsigned int inLength,
|
||||
inline void sendSysEx(unsigned inLength,
|
||||
const byte* inArray,
|
||||
bool inArrayContainsBoundaries = false);
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ public:
|
|||
DataByte inValuesNibble);
|
||||
inline void sendTimeCodeQuarterFrame(DataByte inData);
|
||||
|
||||
inline void sendSongPosition(unsigned int inBeats);
|
||||
inline void sendSongPosition(unsigned inBeats);
|
||||
inline void sendSongSelect(DataByte inSongNumber);
|
||||
inline void sendTuneRequest();
|
||||
inline void sendRealTime(MidiType inType);
|
||||
|
|
@ -109,7 +109,7 @@ public:
|
|||
inline DataByte getData1() const;
|
||||
inline DataByte getData2() const;
|
||||
inline const byte* getSysExArray() const;
|
||||
inline unsigned int getSysExArrayLength() const;
|
||||
inline unsigned getSysExArrayLength() const;
|
||||
inline bool check() const;
|
||||
|
||||
public:
|
||||
|
|
@ -119,6 +119,7 @@ public:
|
|||
public:
|
||||
static inline MidiType getTypeFromStatusByte(byte inStatus);
|
||||
static inline bool isChannelMessage(MidiType inType);
|
||||
static inline bool isRealtimeMessage(MidiType inType);
|
||||
|
||||
private:
|
||||
bool inputFilter(Channel inChannel);
|
||||
|
|
@ -130,8 +131,8 @@ private:
|
|||
Channel mInputChannel;
|
||||
|
||||
byte mPendingMessage[3]; // SysEx are dumped into mMessage directly.
|
||||
unsigned int mPendingMessageExpectedLenght;
|
||||
unsigned int mPendingMessageIndex; // Extended to unsigned int for larger SysEx payloads.
|
||||
unsigned mPendingMessageExpectedLenght;
|
||||
unsigned mPendingMessageIndex; // Extended to unsigned for larger SysEx payloads.
|
||||
Message mMessage;
|
||||
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ public:
|
|||
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend));
|
||||
inline void setHandleSystemExclusive(void (*fptr)(byte * array, byte size));
|
||||
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
|
||||
inline void setHandleSongPosition(void (*fptr)(unsigned int beats));
|
||||
inline void setHandleSongPosition(void (*fptr)(unsigned beats));
|
||||
inline void setHandleSongSelect(void (*fptr)(byte songnumber));
|
||||
inline void setHandleTuneRequest(void (*fptr)(void));
|
||||
inline void setHandleClock(void (*fptr)(void));
|
||||
|
|
@ -175,7 +176,7 @@ private:
|
|||
void (*mPitchBendCallback)(byte channel, int);
|
||||
void (*mSystemExclusiveCallback)(byte * array, byte size);
|
||||
void (*mTimeCodeQuarterFrameCallback)(byte data);
|
||||
void (*mSongPositionCallback)(unsigned int beats);
|
||||
void (*mSongPositionCallback)(unsigned beats);
|
||||
void (*mSongSelectCallback)(byte songnumber);
|
||||
void (*mTuneRequestCallback)(void);
|
||||
void (*mClockCallback)(void);
|
||||
|
|
@ -196,20 +197,20 @@ private:
|
|||
#if MIDI_BUILD_THRU
|
||||
|
||||
public:
|
||||
inline MidiFilterMode getFilterMode() const;
|
||||
inline bool getThruState() const;
|
||||
|
||||
inline void turnThruOn(MidiFilterMode inThruFilterMode = Full);
|
||||
inline void turnThruOn(ThruFlags inThruFlags = ThruFilterFlags::all);
|
||||
inline void turnThruOff();
|
||||
inline void setThruFilterMode(MidiFilterMode inThruFilterMode);
|
||||
|
||||
inline void setThruFilterMode(ThruFlags inFlags);
|
||||
inline ThruFlags getThruFilterMode() const;
|
||||
inline bool isThruOn() const;
|
||||
inline bool hasThruFlag(byte inFlag) const;
|
||||
|
||||
private:
|
||||
void thruFilter(byte inChannel);
|
||||
inline bool shouldMessageBeForwarded(StatusByte inStatus) const;
|
||||
|
||||
private:
|
||||
bool mThruActivated : 1;
|
||||
MidiFilterMode mThruFilterMode : 7;
|
||||
ThruFlags mThruFlags;
|
||||
bool mForwardCurrentMessage;
|
||||
|
||||
#endif // MIDI_BUILD_THRU
|
||||
|
||||
|
|
|
|||
184
src/MIDI.hpp
184
src/MIDI.hpp
|
|
@ -70,7 +70,7 @@ void MidiInterface<SerialPort>::begin(Channel inChannel)
|
|||
|
||||
mRunningStatus_TX = InvalidType;
|
||||
|
||||
#endif // MIDI_BUILD_OUTPUT && MIDI_USE_RUNNING_STATUS
|
||||
#endif
|
||||
|
||||
|
||||
#if MIDI_BUILD_INPUT
|
||||
|
|
@ -86,16 +86,14 @@ void MidiInterface<SerialPort>::begin(Channel inChannel)
|
|||
mMessage.data1 = 0;
|
||||
mMessage.data2 = 0;
|
||||
|
||||
#endif // MIDI_BUILD_INPUT
|
||||
#endif
|
||||
|
||||
|
||||
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU) // Thru
|
||||
#if MIDI_BUILD_THRU
|
||||
|
||||
mThruFilterMode = Full;
|
||||
mThruActivated = true;
|
||||
|
||||
#endif // Thru
|
||||
mThruFlags = ThruFilterFlags::all;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -268,11 +266,10 @@ template<class SerialPort>
|
|||
void MidiInterface<SerialPort>::sendPitchBend(int inPitchValue,
|
||||
Channel inChannel)
|
||||
{
|
||||
const unsigned int bend = inPitchValue - MIDI_PITCHBEND_MIN;
|
||||
const unsigned bend = inPitchValue - MIDI_PITCHBEND_MIN;
|
||||
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)
|
||||
|
|
@ -293,11 +290,11 @@ void MidiInterface<SerialPort>::sendPitchBend(double inPitchValue,
|
|||
\param inArrayContainsBoundaries When set to 'true', 0xF0 & 0xF7 bytes
|
||||
(start & stop SysEx) will NOT be sent
|
||||
(and therefore must be included in the array).
|
||||
default value for ArrayContainsBoundaries is set to 'false' for compatibility
|
||||
default value for inArrayContainsBoundaries is set to 'false' for compatibility
|
||||
with previous versions of the library.
|
||||
*/
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::sendSysEx(unsigned int inLength,
|
||||
void MidiInterface<SerialPort>::sendSysEx(unsigned inLength,
|
||||
const byte* inArray,
|
||||
bool inArrayContainsBoundaries)
|
||||
{
|
||||
|
|
@ -305,14 +302,14 @@ void MidiInterface<SerialPort>::sendSysEx(unsigned int inLength,
|
|||
{
|
||||
mSerial.write(0xF0);
|
||||
|
||||
for (unsigned int i = 0; i < inLength; ++i)
|
||||
for (unsigned i = 0; i < inLength; ++i)
|
||||
mSerial.write(inArray[i]);
|
||||
|
||||
mSerial.write(0xF7);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < inLength; ++i)
|
||||
for (unsigned i = 0; i < inLength; ++i)
|
||||
mSerial.write(inArray[i]);
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +364,7 @@ void MidiInterface<SerialPort>::sendTimeCodeQuarterFrame(DataByte inData)
|
|||
\param inBeats The number of beats since the start of the song.
|
||||
*/
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::sendSongPosition(unsigned int inBeats)
|
||||
void MidiInterface<SerialPort>::sendSongPosition(unsigned inBeats)
|
||||
{
|
||||
mSerial.write((byte)SongPosition);
|
||||
mSerial.write(inBeats & 0x7F);
|
||||
|
|
@ -400,20 +397,9 @@ void MidiInterface<SerialPort>::sendSongSelect(DataByte inSongNumber)
|
|||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::sendRealTime(MidiType inType)
|
||||
{
|
||||
switch (inType)
|
||||
if (isRealtimeMessage(inType) || inType == TuneRequest)
|
||||
{
|
||||
case TuneRequest: // Not really real-time, but one byte anyway.
|
||||
case Clock:
|
||||
case Start:
|
||||
case Stop:
|
||||
case Continue:
|
||||
case ActiveSensing:
|
||||
case SystemReset:
|
||||
mSerial.write((byte)inType);
|
||||
break;
|
||||
default:
|
||||
// Invalid Real Time marker
|
||||
break;
|
||||
}
|
||||
|
||||
// Do not cancel Running Status for real-time messages as they can be
|
||||
|
|
@ -470,22 +456,13 @@ bool MidiInterface<SerialPort>::read(Channel inChannel)
|
|||
if (inChannel >= MIDI_CHANNEL_OFF)
|
||||
return false; // MIDI Input disabled.
|
||||
|
||||
if (parse())
|
||||
if (parse() && inputFilter(inChannel))
|
||||
{
|
||||
if (inputFilter(inChannel))
|
||||
{
|
||||
|
||||
#if (MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
|
||||
thruFilter(inChannel);
|
||||
#endif
|
||||
|
||||
#if MIDI_USE_CALLBACKS
|
||||
launchCallback();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -777,30 +754,17 @@ bool MidiInterface<SerialPort>::inputFilter(Channel inChannel)
|
|||
{
|
||||
// This method handles recognition of channel
|
||||
// (to know if the message is destinated to the Arduino)
|
||||
|
||||
if (mMessage.type == InvalidType)
|
||||
return false;
|
||||
|
||||
// First, check if the received message is Channel
|
||||
if (mMessage.type >= NoteOff && mMessage.type <= PitchBend)
|
||||
{
|
||||
// Then we need to know if we listen to it
|
||||
if ((mMessage.channel == mInputChannel) ||
|
||||
(mInputChannel == MIDI_CHANNEL_OMNI))
|
||||
if (isChannelMessage(mMessage.type))
|
||||
{
|
||||
return (mInputChannel == MIDI_CHANNEL_OMNI ||
|
||||
mInputChannel == mMessage.channel);
|
||||
}
|
||||
|
||||
// Other message types are always received.
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't listen to this channel
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// System messages are always received
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Private method: reset input attributes
|
||||
|
|
@ -865,9 +829,9 @@ const byte* MidiInterface<SerialPort>::getSysExArray() const
|
|||
\return The array's length, in bytes.
|
||||
*/
|
||||
template<class SerialPort>
|
||||
unsigned int MidiInterface<SerialPort>::getSysExArrayLength() const
|
||||
unsigned MidiInterface<SerialPort>::getSysExArrayLength() const
|
||||
{
|
||||
const unsigned int size = ((unsigned)(mMessage.data2) << 8) | mMessage.data1;
|
||||
const unsigned size = ((unsigned)(mMessage.data2) << 8) | mMessage.data1;
|
||||
return (size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : size;
|
||||
}
|
||||
|
||||
|
|
@ -927,6 +891,17 @@ bool MidiInterface<SerialPort>::isChannelMessage(MidiType inType)
|
|||
inType == ProgramChange);
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
bool MidiInterface<SerialPort>::isRealtimeMessage(MidiType inType)
|
||||
{
|
||||
return inType == Clock ||
|
||||
inType == Start ||
|
||||
inType == Stop ||
|
||||
inType == Continue ||
|
||||
inType == ActiveSensing ||
|
||||
inType == SystemReset;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if MIDI_USE_CALLBACKS
|
||||
|
|
@ -944,7 +919,7 @@ template<class SerialPort> void MidiInterface<SerialPort>::setHandleAfterTouchCh
|
|||
template<class SerialPort> void MidiInterface<SerialPort>::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleSystemExclusive(void (*fptr)(byte* array, byte size)) { mSystemExclusiveCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleSongPosition(void (*fptr)(unsigned int beats)) { mSongPositionCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
|
||||
template<class SerialPort> void MidiInterface<SerialPort>::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
|
||||
|
|
@ -1041,55 +1016,82 @@ void MidiInterface<SerialPort>::launchCallback()
|
|||
// Thru
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
|
||||
#if MIDI_BUILD_THRU
|
||||
|
||||
/*! \addtogroup thru
|
||||
@{
|
||||
*/
|
||||
|
||||
/*! \brief Set the filter for thru mirroring
|
||||
\param inThruFilterMode a filter mode
|
||||
|
||||
@see MidiFilterMode
|
||||
*/
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::setThruFilterMode(MidiFilterMode inThruFilterMode)
|
||||
void MidiInterface<SerialPort>::turnThruOn(ThruFlags inFlags)
|
||||
{
|
||||
mThruFilterMode = inThruFilterMode;
|
||||
if (mThruFilterMode != Off)
|
||||
mThruActivated = true;
|
||||
else
|
||||
mThruActivated = false;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
MidiFilterMode MidiInterface<SerialPort>::getFilterMode() const
|
||||
{
|
||||
return mThruFilterMode;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
bool MidiInterface<SerialPort>::getThruState() const
|
||||
{
|
||||
return mThruActivated;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::turnThruOn(MidiFilterMode inThruFilterMode)
|
||||
{
|
||||
mThruActivated = true;
|
||||
mThruFilterMode = inThruFilterMode;
|
||||
mThruFlags = inFlags;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::turnThruOff()
|
||||
{
|
||||
mThruActivated = false;
|
||||
mThruFilterMode = Off;
|
||||
mThruFlags = ThruFilterFlags::off;
|
||||
}
|
||||
|
||||
/*! \brief Set the filter for thru mirroring
|
||||
\param inThruFilterMode a filter mode
|
||||
|
||||
@see ThruFilterFlags
|
||||
*/
|
||||
template<class SerialPort>
|
||||
void MidiInterface<SerialPort>::setThruFilterMode(ThruFlags inFlags)
|
||||
{
|
||||
mThruFlags = inFlags;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
ThruFlags MidiInterface<SerialPort>::getThruFilterMode() const
|
||||
{
|
||||
return mThruFlags;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
bool MidiInterface<SerialPort>::isThruOn() const
|
||||
{
|
||||
return mThruFlags != ThruFilterFlags::off;
|
||||
}
|
||||
|
||||
template<class SerialPort>
|
||||
bool MidiInterface<SerialPort>::hasThruFlag(byte inFlag) const
|
||||
{
|
||||
return mThruFlags & inFlag;
|
||||
}
|
||||
|
||||
/*! @} */ // End of doc group MIDI Thru
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
template<class SerialPort>
|
||||
bool MidiInterface<SerialPort>::shouldMessageBeForwarded(StatusByte inStatus) const
|
||||
{
|
||||
if (isChannelMessage(inStatus))
|
||||
{
|
||||
const Channel channel = getChannel(inStatus);
|
||||
const bool forwardSame = hasThruFlag(ThruFilterFlags::channelSame);
|
||||
const bool forwardDiff = hasThruFlag(ThruFilterFlags::channelDifferent);
|
||||
return (forwardSame && mInputChannel == channel) ||
|
||||
(forwardDiff && mInputChannel != channel);
|
||||
}
|
||||
else if (isRealtimeMessage(inStatus))
|
||||
{
|
||||
return hasThruFlag(ThruFilterFlags::realtime);
|
||||
}
|
||||
else if (inStatus == SystemExclusive)
|
||||
{
|
||||
return hasThruFlag(ThruFilterFlags::system);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown message or junk
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called upon reception of a message
|
||||
// and takes care of Thru filtering and sending.
|
||||
template<class SerialPort>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,23 @@ enum MidiFilterMode
|
|||
DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back.
|
||||
};
|
||||
|
||||
struct ThruFilterFlags
|
||||
{
|
||||
enum
|
||||
{
|
||||
off = 0
|
||||
|
||||
, channelSame = 1
|
||||
, channelDifferent = 2
|
||||
, channel = channelSame | channelDifferent
|
||||
, system = 4
|
||||
, realtime = 8
|
||||
, all = channel | system | realtime
|
||||
};
|
||||
};
|
||||
|
||||
typedef byte ThruFlags;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*! \brief Enumeration of Control Change command numbers.
|
||||
|
|
|
|||
Loading…
Reference in New Issue