33 template<
class SerialPort,
class Settings>
39 , mPendingMessageExpectedLenght(0)
40 , mPendingMessageIndex(0)
41 , mCurrentRpnNumber(0xffff)
42 , mCurrentNrpnNumber(0xffff)
43 , mThruActivated(true)
44 , mThruFilterMode(
Thru::Full)
48 mAfterTouchPolyCallback = 0;
49 mControlChangeCallback = 0;
50 mProgramChangeCallback = 0;
51 mAfterTouchChannelCallback = 0;
52 mPitchBendCallback = 0;
53 mSystemExclusiveCallback = 0;
54 mTimeCodeQuarterFrameCallback = 0;
55 mSongPositionCallback = 0;
56 mSongSelectCallback = 0;
57 mTuneRequestCallback = 0;
60 mContinueCallback = 0;
62 mActiveSensingCallback = 0;
63 mSystemResetCallback = 0;
70 template<
class SerialPort,
class Settings>
83 template<
class SerialPort,
class Settings>
88 mSerial.
template open<Settings::BaudRate>();
90 mSerial.begin(Settings::BaudRate);
93 mInputChannel = inChannel;
97 mPendingMessageIndex = 0;
98 mPendingMessageExpectedLenght = 0;
100 mCurrentRpnNumber = 0xffff;
101 mCurrentNrpnNumber = 0xffff;
103 mMessage.
valid =
false;
110 mThruActivated =
true;
132 template<
class SerialPort,
class Settings>
152 const StatusByte status = getStatus(inType, inChannel);
154 if (Settings::UseRunningStatus)
156 if (mRunningStatus_TX != status)
159 mRunningStatus_TX = status;
160 mSerial.write(mRunningStatus_TX);
166 mSerial.write(status);
170 mSerial.write(inData1);
173 mSerial.write(inData2);
193 template<
class SerialPort,
class Settings>
198 send(
NoteOn, inNoteNumber, inVelocity, inChannel);
212 template<
class SerialPort,
class Settings>
217 send(
NoteOff, inNoteNumber, inVelocity, inChannel);
224 template<
class SerialPort,
class Settings>
237 template<
class SerialPort,
class Settings>
252 template<
class SerialPort,
class Settings>
264 template<
class SerialPort,
class Settings>
277 template<
class SerialPort,
class Settings>
291 template<
class SerialPort,
class Settings>
296 send(
PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel);
306 template<
class SerialPort,
class Settings>
311 const int value = int(inPitchValue *
double(scale));
324 template<
class SerialPort,
class Settings>
327 bool inArrayContainsBoundaries)
329 const bool writeBeginEndBytes = !inArrayContainsBoundaries;
331 if (writeBeginEndBytes)
336 for (
unsigned i = 0; i < inLength; ++i)
338 mSerial.write(inArray[i]);
341 if (writeBeginEndBytes)
346 if (Settings::UseRunningStatus)
357 template<
class SerialPort,
class Settings>
362 if (Settings::UseRunningStatus)
374 template<
class SerialPort,
class Settings>
378 const byte data = (((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f));
388 template<
class SerialPort,
class Settings>
392 mSerial.write(inData);
394 if (Settings::UseRunningStatus)
403 template<
class SerialPort,
class Settings>
407 mSerial.write(inBeats & 0x7f);
408 mSerial.write((inBeats >> 7) & 0x7f);
410 if (Settings::UseRunningStatus)
417 template<
class SerialPort,
class Settings>
421 mSerial.write(inSongNumber & 0x7f);
423 if (Settings::UseRunningStatus)
435 template<
class SerialPort,
class Settings>
449 mSerial.write((
byte)inType);
461 template<
class SerialPort,
class Settings>
465 if (mCurrentRpnNumber != inNumber)
467 const byte numMsb = 0x7f & (inNumber >> 7);
468 const byte numLsb = 0x7f & inNumber;
471 mCurrentRpnNumber = inNumber;
479 template<
class SerialPort,
class Settings>
483 const byte valMsb = 0x7f & (inValue >> 7);
484 const byte valLsb = 0x7f & inValue;
494 template<
class SerialPort,
class Settings>
506 template<
class SerialPort,
class Settings>
516 template<
class SerialPort,
class Settings>
527 template<
class SerialPort,
class Settings>
532 mCurrentRpnNumber = 0xffff;
541 template<
class SerialPort,
class Settings>
545 if (mCurrentNrpnNumber != inNumber)
547 const byte numMsb = 0x7f & (inNumber >> 7);
548 const byte numLsb = 0x7f & inNumber;
551 mCurrentNrpnNumber = inNumber;
559 template<
class SerialPort,
class Settings>
563 const byte valMsb = 0x7f & (inValue >> 7);
564 const byte valLsb = 0x7f & inValue;
574 template<
class SerialPort,
class Settings>
586 template<
class SerialPort,
class Settings>
596 template<
class SerialPort,
class Settings>
607 template<
class SerialPort,
class Settings>
612 mCurrentNrpnNumber = 0xffff;
619 template<
class SerialPort,
class Settings>
623 return ((
byte)inType | ((inChannel - 1) & 0x0f));
642 template<
class SerialPort,
class Settings>
645 return read(mInputChannel);
650 template<
class SerialPort,
class Settings>
659 handleNullVelocityNoteOnAsNoteOff();
660 const bool channelMatch = inputFilter(inChannel);
667 thruFilter(inChannel);
675 template<
class SerialPort,
class Settings>
678 if (mSerial.available() == 0)
691 const byte extracted = mSerial.read();
694 if (extracted == 0xf9 || extracted == 0xfd)
696 if (Settings::Use1ByteParsing)
706 if (mPendingMessageIndex == 0)
709 mPendingMessage[0] = extracted;
718 if (extracted < 0x80)
720 mPendingMessage[0] = mRunningStatus_RX;
721 mPendingMessage[1] = extracted;
722 mPendingMessageIndex = 1;
744 mMessage.
valid =
true;
748 mPendingMessageIndex = 0;
749 mPendingMessageExpectedLenght = 0;
759 mPendingMessageExpectedLenght = 2;
769 mPendingMessageExpectedLenght = 3;
788 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
793 mMessage.
data1 = mPendingMessage[1];
796 mPendingMessageIndex = 0;
797 mPendingMessageExpectedLenght = 0;
798 mMessage.
valid =
true;
804 mPendingMessageIndex++;
807 if (Settings::Use1ByteParsing)
822 if (extracted >= 0x80)
846 mMessage.
valid =
true;
854 mMessage.
sysexArray[mPendingMessageIndex++] = 0xf7;
858 mMessage.
data1 = mPendingMessageIndex & 0xff;
859 mMessage.
data2 = mPendingMessageIndex >> 8;
861 mMessage.
valid =
true;
880 mMessage.
sysexArray[mPendingMessageIndex] = extracted;
882 mPendingMessage[mPendingMessageIndex] = extracted;
885 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
903 mMessage.
data1 = mPendingMessage[1];
906 mMessage.
data2 = mPendingMessageExpectedLenght == 3 ? mPendingMessage[2] : 0;
909 mPendingMessageIndex = 0;
910 mPendingMessageExpectedLenght = 0;
912 mMessage.
valid =
true;
915 switch (mMessage.
type)
925 mRunningStatus_RX = mPendingMessage[0];
938 mPendingMessageIndex++;
940 if (Settings::Use1ByteParsing)
955 template<
class SerialPort,
class Settings>
958 if (Settings::HandleNullVelocityNoteOnAsNoteOff &&
966 template<
class SerialPort,
class Settings>
976 if ((mMessage.
channel == inChannel) ||
995 template<
class SerialPort,
class Settings>
998 mPendingMessageIndex = 0;
999 mPendingMessageExpectedLenght = 0;
1009 template<
class SerialPort,
class Settings>
1012 return mMessage.
type;
1020 template<
class SerialPort,
class Settings>
1027 template<
class SerialPort,
class Settings>
1030 return mMessage.
data1;
1034 template<
class SerialPort,
class Settings>
1037 return mMessage.
data2;
1044 template<
class SerialPort,
class Settings>
1055 template<
class SerialPort,
class Settings>
1062 template<
class SerialPort,
class Settings>
1065 return mMessage.
valid;
1070 template<
class SerialPort,
class Settings>
1073 return mInputChannel;
1080 template<
class SerialPort,
class Settings>
1083 mInputChannel = inChannel;
1093 template<
class SerialPort,
class Settings>
1096 if ((inStatus < 0x80) ||
1097 (inStatus == 0xf4) ||
1098 (inStatus == 0xf5) ||
1099 (inStatus == 0xf9) ||
1105 if (inStatus < 0xf0)
1116 template<
class SerialPort,
class Settings>
1119 return (inStatus & 0x0f) + 1;
1122 template<
class SerialPort,
class Settings>
1165 template<
class SerialPort,
class Settings>
1170 case NoteOff: mNoteOffCallback = 0;
break;
1171 case NoteOn: mNoteOnCallback = 0;
break;
1176 case PitchBend: mPitchBendCallback = 0;
break;
1180 case SongSelect: mSongSelectCallback = 0;
break;
1181 case TuneRequest: mTuneRequestCallback = 0;
break;
1182 case Clock: mClockCallback = 0;
break;
1183 case Start: mStartCallback = 0;
break;
1184 case Continue: mContinueCallback = 0;
break;
1185 case Stop: mStopCallback = 0;
break;
1187 case SystemReset: mSystemResetCallback = 0;
break;
1196 template<
class SerialPort,
class Settings>
1200 switch (mMessage.
type)
1203 case NoteOff:
if (mNoteOffCallback != 0) mNoteOffCallback(mMessage.
channel, mMessage.
data1, mMessage.
data2);
break;
1204 case NoteOn:
if (mNoteOnCallback != 0) mNoteOnCallback(mMessage.
channel, mMessage.
data1, mMessage.
data2);
break;
1207 case Clock:
if (mClockCallback != 0) mClockCallback();
break;
1208 case Start:
if (mStartCallback != 0) mStartCallback();
break;
1209 case Continue:
if (mContinueCallback != 0) mContinueCallback();
break;
1210 case Stop:
if (mStopCallback != 0) mStopCallback();
break;
1211 case ActiveSensing:
if (mActiveSensingCallback != 0) mActiveSensingCallback();
break;
1223 case TimeCodeQuarterFrame:
if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.
data1);
break;
1224 case SongPosition:
if (mSongPositionCallback != 0) mSongPositionCallback((mMessage.
data1 & 0x7f) | ((mMessage.
data2 & 0x7f) << 7));
break;
1225 case SongSelect:
if (mSongSelectCallback != 0) mSongSelectCallback(mMessage.
data1);
break;
1226 case TuneRequest:
if (mTuneRequestCallback != 0) mTuneRequestCallback();
break;
1228 case SystemReset:
if (mSystemResetCallback != 0) mSystemResetCallback();
break;
1251 template<
class SerialPort,
class Settings>
1254 mThruFilterMode = inThruFilterMode;
1255 mThruActivated = mThruFilterMode !=
Thru::Off;
1258 template<
class SerialPort,
class Settings>
1261 return mThruFilterMode;
1264 template<
class SerialPort,
class Settings>
1267 return mThruActivated;
1270 template<
class SerialPort,
class Settings>
1273 mThruActivated =
true;
1274 mThruFilterMode = inThruFilterMode;
1277 template<
class SerialPort,
class Settings>
1280 mThruActivated =
false;
1292 template<
class SerialPort,
class Settings>
1296 if (!mThruActivated || (mThruFilterMode ==
Thru::Off))
1302 const bool filter_condition = ((mMessage.
channel == inChannel) ||
1306 switch (mThruFilterMode)
1316 if (filter_condition)
1326 if (!filter_condition)
1342 switch (mMessage.
type)
void setHandleProgramChange(void(*fptr)(byte channel, byte number))
System Common - Song Position Pointer.
void disconnectCallbackFromType(MidiType inType)
Detach an external function from the given type.
System Common - Song Select.
void setHandleNoteOn(void(*fptr)(byte channel, byte note, byte velocity))
void sendSongSelect(DataByte inSongNumber)
Send a Song Select message.
void setThruFilterMode(Thru::Mode inThruFilterMode)
Set the filter for thru mirroring.
void sendSongPosition(unsigned inBeats)
Send a Song Position Pointer message.
Non-Registered Parameter Number (MSB)
void turnThruOn(Thru::Mode inThruFilterMode=Thru::Full)
#define MIDI_PITCHBEND_MAX
void beginRpn(unsigned inNumber, Channel inChannel)
Start a Registered Parameter Number frame.
static const unsigned sSysExMaxSize
System Real Time - Timing Clock.
void sendProgramChange(DataByte inProgramNumber, Channel inChannel)
Send a Program Change message.
MidiType getType() const
Get the last received message's type.
DataByte getData2() const
Get the second data byte of the last received message.
#define BEGIN_MIDI_NAMESPACE
System Common - MIDI Time Code Quarter Frame.
Thru disabled (nothing passes through).
#define MIDI_PITCHBEND_MIN
DataByte sysexArray[sSysExMaxSize]
Channel getChannel() const
Get the channel of the message stored in the structure.
void setHandleSystemExclusive(void(*fptr)(byte *array, unsigned size))
#define END_MIDI_NAMESPACE
void setHandleSongSelect(void(*fptr)(byte songnumber))
unsigned getSysExArrayLength() const
Get the lenght of the System Exclusive array.
Only the messages on the Input Channel will be sent back.
bool read()
Read messages from the serial port using the main input channel.
DataByte getData1() const
Get the first data byte of the last received message.
void setHandleClock(void(*fptr)(void))
Channel (monophonic) AfterTouch.
void beginNrpn(unsigned inNumber, Channel inChannel)
Start a Non-Registered Parameter Number frame.
Non-Registered Parameter Number (LSB)
void begin(Channel inChannel=1)
Call the begin method in the setup() function of the Arduino.
void sendRealTime(MidiType inType)
Send a Real Time (one byte) message.
static Channel getChannelFromStatusByte(byte inStatus)
Returns channel in the range 1-16.
void setHandleStart(void(*fptr)(void))
System Real Time - Continue.
void endRpn(Channel inChannel)
Terminate an RPN frame. This will send a Null Function to deselect the currently selected RPN...
#define MIDI_CHANNEL_OMNI
void setInputChannel(Channel inChannel)
Set the value for the input MIDI channel.
void setHandleSystemReset(void(*fptr)(void))
System Real Time - Start.
bool getThruState() const
Channel getInputChannel() const
void endNrpn(Channel inChannel)
Terminate an NRPN frame. This will send a Null Function to deselect the currently selected NRPN...
Registered Parameter Number (MSB)
void sendAfterTouch(DataByte inPressure, Channel inChannel)
Send a MonoPhonic AfterTouch message (applies to all notes)
void sendPolyPressure(DataByte inNoteNumber, DataByte inPressure, Channel inChannel) __attribute__((deprecated))
Send a Polyphonic AfterTouch message (applies to a specified note)
void sendRpnDecrement(byte inAmount, Channel inChannel)
void sendNrpnValue(unsigned inValue, Channel inChannel)
Send a 14-bit value for the currently selected NRPN number.
void sendControlChange(DataByte inControlNumber, DataByte inControlValue, Channel inChannel)
Send a Control Change message.
void sendTimeCodeQuarterFrame(DataByte inTypeNibble, DataByte inValuesNibble)
Send a MIDI Time Code Quarter Frame.
void sendNrpnDecrement(byte inAmount, Channel inChannel)
void setHandleSongPosition(void(*fptr)(unsigned beats))
Control Change / Channel Mode.
Thru::Mode getFilterMode() const
void sendPitchBend(int inPitchValue, Channel inChannel)
Send a Pitch Bend message using a signed integer value.
System Common - Tune Request.
static MidiType getTypeFromStatusByte(byte inStatus)
Extract an enumerated MIDI type from a status byte.
void setHandleActiveSensing(void(*fptr)(void))
MidiInterface(SerialPort &inSerial)
Constructor for MidiInterface.
static bool isChannelMessage(MidiType inType)
void setHandleTimeCodeQuarterFrame(void(*fptr)(byte data))
void sendTuneRequest()
Send a Tune Request message.
void setHandleContinue(void(*fptr)(void))
void sendNrpnIncrement(byte inAmount, Channel inChannel)
void sendRpnValue(unsigned inValue, Channel inChannel)
Send a 14-bit value for the currently selected RPN number.
void send(MidiType inType, DataByte inData1, DataByte inData2, Channel inChannel)
Generate and send a MIDI message from the values given.
void sendSysEx(unsigned inLength, const byte *inArray, bool inArrayContainsBoundaries=false)
Generate and send a System Exclusive frame.
void setHandleNoteOff(void(*fptr)(byte channel, byte note, byte velocity))
bool check() const
Check if a valid message is stored in the structure.
All the messages but the ones on the Input Channel will be sent back.
void setHandlePitchBend(void(*fptr)(byte channel, int bend))
unsigned getSysExSize() const
void setHandleStop(void(*fptr)(void))
void sendNoteOn(DataByte inNoteNumber, DataByte inVelocity, Channel inChannel)
Send a Note On message.
const byte * getSysExArray() const
Get the System Exclusive byte array.
System Real Time - Active Sensing.
Fully enabled Thru (every incoming message is sent back).
void setHandleTuneRequest(void(*fptr)(void))
System Real Time - System Reset.
~MidiInterface()
Destructor for MidiInterface.
void setHandleControlChange(void(*fptr)(byte channel, byte number, byte value))
void sendNoteOff(DataByte inNoteNumber, DataByte inVelocity, Channel inChannel)
Send a Note Off message.
The main class for MIDI handling. It is templated over the type of serial port to provide abstraction...
void setHandleAfterTouchChannel(void(*fptr)(byte channel, byte pressure))
Registered Parameter Number (LSB)
void sendRpnIncrement(byte inAmount, Channel inChannel)
void setHandleAfterTouchPoly(void(*fptr)(byte channel, byte note, byte pressure))