added send(MidiMessage), added (untested) bridge example
added send(MidiMessage) for Bridge application (that convert MIDI transport x into MIDI transport y), avoiding parsing entry a stream, setting up all callback - whilst this allows for passing the content, without to much processing/parsing. Had to move mPendingMessageExpectedLenght into MidiMessage to avoid parsing the data again, just to know the size Added Bridge example (untested)
This commit is contained in:
parent
8905d36c0e
commit
8893642b27
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include <MIDI.h>
|
||||||
|
#include <USB-MIDI.h>
|
||||||
|
|
||||||
|
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
|
||||||
|
USBMIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
void handleMessage1(TypedMidiInterface::MidiMessage message)
|
||||||
|
{
|
||||||
|
MIDI.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMessage(TypedMidiInterface::MidiMessage message)
|
||||||
|
{
|
||||||
|
MIDI1.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
MIDI.setHandleMessage(handleMessage);
|
||||||
|
MIDI1.setHandleMessage(handleMessage1);
|
||||||
|
|
||||||
|
// Initiate MIDI communications, listen to all channels
|
||||||
|
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||||
|
MIDI1.begin(MIDI_CHANNEL_OMNI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
// Call MIDI.read the fastest you can for real-time performance.
|
||||||
|
MIDI.read();
|
||||||
|
MIDI1.read();
|
||||||
|
}
|
||||||
|
|
@ -24,11 +24,6 @@ void handleNoteOff(byte channel, byte pitch, byte velocity)
|
||||||
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
|
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleMessage(__mismt::MidiMessage message)
|
|
||||||
{
|
|
||||||
// Do something when the message.
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
|
|
@ -40,8 +35,6 @@ void setup()
|
||||||
// Do the same for NoteOffs
|
// Do the same for NoteOffs
|
||||||
MIDI.setHandleNoteOff(handleNoteOff);
|
MIDI.setHandleNoteOff(handleNoteOff);
|
||||||
|
|
||||||
MIDI.setHandleMessage(handleMessage);
|
|
||||||
|
|
||||||
// Initiate MIDI communications, listen to all channels
|
// Initiate MIDI communications, listen to all channels
|
||||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ public:
|
||||||
Channel inChannel);
|
Channel inChannel);
|
||||||
inline void endNrpn(Channel inChannel);
|
inline void endNrpn(Channel inChannel);
|
||||||
|
|
||||||
|
inline void send(MidiMessage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void send(MidiType inType,
|
void send(MidiType inType,
|
||||||
DataByte inData1,
|
DataByte inData1,
|
||||||
|
|
@ -239,7 +241,6 @@ private:
|
||||||
StatusByte mRunningStatus_RX;
|
StatusByte mRunningStatus_RX;
|
||||||
StatusByte mRunningStatus_TX;
|
StatusByte mRunningStatus_TX;
|
||||||
byte mPendingMessage[3];
|
byte mPendingMessage[3];
|
||||||
unsigned mPendingMessageExpectedLenght;
|
|
||||||
unsigned mPendingMessageIndex;
|
unsigned mPendingMessageIndex;
|
||||||
unsigned mCurrentRpnNumber;
|
unsigned mCurrentRpnNumber;
|
||||||
unsigned mCurrentNrpnNumber;
|
unsigned mCurrentNrpnNumber;
|
||||||
|
|
|
||||||
62
src/MIDI.hpp
62
src/MIDI.hpp
|
|
@ -36,7 +36,6 @@ inline MidiInterface<Transport, Settings, Platform>::MidiInterface(Transport& in
|
||||||
, mInputChannel(0)
|
, mInputChannel(0)
|
||||||
, mRunningStatus_RX(InvalidType)
|
, mRunningStatus_RX(InvalidType)
|
||||||
, mRunningStatus_TX(InvalidType)
|
, mRunningStatus_TX(InvalidType)
|
||||||
, mPendingMessageExpectedLenght(0)
|
|
||||||
, mPendingMessageIndex(0)
|
, mPendingMessageIndex(0)
|
||||||
, mCurrentRpnNumber(0xffff)
|
, mCurrentRpnNumber(0xffff)
|
||||||
, mCurrentNrpnNumber(0xffff)
|
, mCurrentNrpnNumber(0xffff)
|
||||||
|
|
@ -94,7 +93,6 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
|
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
|
||||||
|
|
||||||
mCurrentRpnNumber = 0xffff;
|
mCurrentRpnNumber = 0xffff;
|
||||||
mCurrentNrpnNumber = 0xffff;
|
mCurrentNrpnNumber = 0xffff;
|
||||||
|
|
@ -107,6 +105,7 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||||
mMessage.channel = 0;
|
mMessage.channel = 0;
|
||||||
mMessage.data1 = 0;
|
mMessage.data1 = 0;
|
||||||
mMessage.data2 = 0;
|
mMessage.data2 = 0;
|
||||||
|
mMessage.length = 0;
|
||||||
|
|
||||||
mThruFilterMode = Thru::Full;
|
mThruFilterMode = Thru::Full;
|
||||||
mThruActivated = false;
|
mThruActivated = false;
|
||||||
|
|
@ -120,6 +119,45 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \brief Send a MIDI message.
|
||||||
|
\param inMessage The message
|
||||||
|
|
||||||
|
This method is used when you want to send a Message that has not been constructed
|
||||||
|
by the library, but by an external source.
|
||||||
|
This method does *not* check against any of the constraints.
|
||||||
|
Typically this function is use by MIDI Bridges taking MIDI messages and passing
|
||||||
|
them thru.
|
||||||
|
*/
|
||||||
|
template<class Transport, class Settings, class Platform>
|
||||||
|
void MidiInterface<Transport, Settings, Platform>::send(MidiMessage inMessage)
|
||||||
|
{
|
||||||
|
if (!inMessage.valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mTransport.beginTransmission(inMessage.type))
|
||||||
|
{
|
||||||
|
const StatusByte status = getStatus(inMessage.type, inMessage.channel);
|
||||||
|
mTransport.write(status);
|
||||||
|
|
||||||
|
if (inMessage.type != MidiType::SystemExclusive)
|
||||||
|
{
|
||||||
|
if (inMessage.length > 1) mTransport.write(inMessage.data1);
|
||||||
|
if (inMessage.length > 2) mTransport.write(inMessage.data2);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// sysexArray does not contain the start and end tags
|
||||||
|
mTransport.write(MidiType::SystemExclusiveStart);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < inMessage.getSysExSize(); i++)
|
||||||
|
mTransport.write(inMessage.sysexArray[i]);
|
||||||
|
|
||||||
|
mTransport.write(MidiType::SystemExclusiveEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTransport.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Generate and send a MIDI message from the values given.
|
/*! \brief Generate and send a MIDI message from the values given.
|
||||||
\param inType The message type (see type defines for reference)
|
\param inType The message type (see type defines for reference)
|
||||||
\param inData1 The first data byte.
|
\param inData1 The first data byte.
|
||||||
|
|
@ -764,12 +802,12 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
mMessage.channel = 0;
|
mMessage.channel = 0;
|
||||||
mMessage.data1 = 0;
|
mMessage.data1 = 0;
|
||||||
mMessage.data2 = 0;
|
mMessage.data2 = 0;
|
||||||
|
mMessage.length = 0;
|
||||||
mMessage.valid = true;
|
mMessage.valid = true;
|
||||||
|
|
||||||
// Do not reset all input attributes, Running Status must remain unchanged.
|
// Do not reset all input attributes, Running Status must remain unchanged.
|
||||||
// We still need to reset these
|
// We still need to reset these
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -779,7 +817,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
case AfterTouchChannel:
|
case AfterTouchChannel:
|
||||||
case TimeCodeQuarterFrame:
|
case TimeCodeQuarterFrame:
|
||||||
case SongSelect:
|
case SongSelect:
|
||||||
mPendingMessageExpectedLenght = 2;
|
mMessage.length = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 3 bytes messages
|
// 3 bytes messages
|
||||||
|
|
@ -789,14 +827,14 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
case PitchBend:
|
case PitchBend:
|
||||||
case AfterTouchPoly:
|
case AfterTouchPoly:
|
||||||
case SongPosition:
|
case SongPosition:
|
||||||
mPendingMessageExpectedLenght = 3;
|
mMessage.length = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SystemExclusiveStart:
|
case SystemExclusiveStart:
|
||||||
case SystemExclusiveEnd:
|
case SystemExclusiveEnd:
|
||||||
// The message can be any lenght
|
// The message can be any lenght
|
||||||
// between 3 and MidiMessage::sSysExMaxSize bytes
|
// between 3 and MidiMessage::sSysExMaxSize bytes
|
||||||
mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize;
|
mMessage.length = MidiMessage::sSysExMaxSize;
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
mMessage.sysexArray[0] = pendingType;
|
mMessage.sysexArray[0] = pendingType;
|
||||||
break;
|
break;
|
||||||
|
|
@ -809,7 +847,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
|
if (mPendingMessageIndex >= (mMessage.length - 1))
|
||||||
{
|
{
|
||||||
// Reception complete
|
// Reception complete
|
||||||
mMessage.type = pendingType;
|
mMessage.type = pendingType;
|
||||||
|
|
@ -818,7 +856,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
mMessage.data2 = 0; // Completed new message has 1 data byte
|
mMessage.data2 = 0; // Completed new message has 1 data byte
|
||||||
|
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
mMessage.length = 0;
|
||||||
mMessage.valid = true;
|
mMessage.valid = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -909,7 +947,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
mPendingMessage[mPendingMessageIndex] = extracted;
|
mPendingMessage[mPendingMessageIndex] = extracted;
|
||||||
|
|
||||||
// Now we are going to check if we have reached the end of the message
|
// Now we are going to check if we have reached the end of the message
|
||||||
if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
|
if (mPendingMessageIndex >= (mMessage.length - 1))
|
||||||
{
|
{
|
||||||
// "FML" case: fall down here with an overflown SysEx..
|
// "FML" case: fall down here with an overflown SysEx..
|
||||||
// This means we received the last possible data byte that can fit
|
// This means we received the last possible data byte that can fit
|
||||||
|
|
@ -930,11 +968,11 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
||||||
mMessage.data1 = mPendingMessage[1];
|
mMessage.data1 = mPendingMessage[1];
|
||||||
|
|
||||||
// Save data2 only if applicable
|
// Save data2 only if applicable
|
||||||
mMessage.data2 = mPendingMessageExpectedLenght == 3 ? mPendingMessage[2] : 0;
|
mMessage.data2 = mMessage.length == 3 ? mPendingMessage[2] : 0;
|
||||||
|
|
||||||
// Reset local variables
|
// Reset local variables
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
mMessage.length = 0;
|
||||||
|
|
||||||
mMessage.valid = true;
|
mMessage.valid = true;
|
||||||
|
|
||||||
|
|
@ -1014,7 +1052,7 @@ template<class Transport, class Settings, class Platform>
|
||||||
inline void MidiInterface<Transport, Settings, Platform>::resetInput()
|
inline void MidiInterface<Transport, Settings, Platform>::resetInput()
|
||||||
{
|
{
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
mMessage.length = 0;
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,10 @@ struct Message
|
||||||
*/
|
*/
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
|
/*! Total Length of the message.
|
||||||
|
*/
|
||||||
|
unsigned length;
|
||||||
|
|
||||||
inline unsigned getSysExSize() const
|
inline unsigned getSysExSize() const
|
||||||
{
|
{
|
||||||
const unsigned size = unsigned(data2) << 8 | data1;
|
const unsigned size = unsigned(data2) << 8 | data1;
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ private:
|
||||||
*/
|
*/
|
||||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||||
typedef MIDI_NAMESPACE::serialMIDI<Type> __smt;\
|
typedef MIDI_NAMESPACE::serialMIDI<Type> __smt;\
|
||||||
typedef MIDI_NAMESPACE::MidiInterface<__smt> __mismt;\
|
typedef MIDI_NAMESPACE::MidiInterface<__smt> TypedMidiInterface;\
|
||||||
__smt serialMidi(SerialPort);\
|
__smt serialMidi(SerialPort);\
|
||||||
__mismt Name((__smt&)serialMidi);
|
TypedMidiInterface Name((__smt&)serialMidi);
|
||||||
|
|
||||||
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||||
// Leonardo, Due and other USB boards use Serial1 by default.
|
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue