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.
|
||||
}
|
||||
|
||||
void handleMessage(__mismt::MidiMessage message)
|
||||
{
|
||||
// Do something when the message.
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void setup()
|
||||
|
|
@ -40,8 +35,6 @@ void setup()
|
|||
// Do the same for NoteOffs
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
|
||||
MIDI.setHandleMessage(handleMessage);
|
||||
|
||||
// Initiate MIDI communications, listen to all channels
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ public:
|
|||
Channel inChannel);
|
||||
inline void endNrpn(Channel inChannel);
|
||||
|
||||
inline void send(MidiMessage);
|
||||
|
||||
public:
|
||||
void send(MidiType inType,
|
||||
DataByte inData1,
|
||||
|
|
@ -239,7 +241,6 @@ private:
|
|||
StatusByte mRunningStatus_RX;
|
||||
StatusByte mRunningStatus_TX;
|
||||
byte mPendingMessage[3];
|
||||
unsigned mPendingMessageExpectedLenght;
|
||||
unsigned mPendingMessageIndex;
|
||||
unsigned mCurrentRpnNumber;
|
||||
unsigned mCurrentNrpnNumber;
|
||||
|
|
|
|||
62
src/MIDI.hpp
62
src/MIDI.hpp
|
|
@ -36,7 +36,6 @@ inline MidiInterface<Transport, Settings, Platform>::MidiInterface(Transport& in
|
|||
, mInputChannel(0)
|
||||
, mRunningStatus_RX(InvalidType)
|
||||
, mRunningStatus_TX(InvalidType)
|
||||
, mPendingMessageExpectedLenght(0)
|
||||
, mPendingMessageIndex(0)
|
||||
, mCurrentRpnNumber(0xffff)
|
||||
, mCurrentNrpnNumber(0xffff)
|
||||
|
|
@ -94,7 +93,6 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
|||
mRunningStatus_RX = InvalidType;
|
||||
|
||||
mPendingMessageIndex = 0;
|
||||
mPendingMessageExpectedLenght = 0;
|
||||
|
||||
mCurrentRpnNumber = 0xffff;
|
||||
mCurrentNrpnNumber = 0xffff;
|
||||
|
|
@ -107,6 +105,7 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
|||
mMessage.channel = 0;
|
||||
mMessage.data1 = 0;
|
||||
mMessage.data2 = 0;
|
||||
mMessage.length = 0;
|
||||
|
||||
mThruFilterMode = Thru::Full;
|
||||
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.
|
||||
\param inType The message type (see type defines for reference)
|
||||
\param inData1 The first data byte.
|
||||
|
|
@ -764,12 +802,12 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
mMessage.channel = 0;
|
||||
mMessage.data1 = 0;
|
||||
mMessage.data2 = 0;
|
||||
mMessage.length = 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;
|
||||
|
||||
return true;
|
||||
break;
|
||||
|
|
@ -779,7 +817,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
case AfterTouchChannel:
|
||||
case TimeCodeQuarterFrame:
|
||||
case SongSelect:
|
||||
mPendingMessageExpectedLenght = 2;
|
||||
mMessage.length = 2;
|
||||
break;
|
||||
|
||||
// 3 bytes messages
|
||||
|
|
@ -789,14 +827,14 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
case PitchBend:
|
||||
case AfterTouchPoly:
|
||||
case SongPosition:
|
||||
mPendingMessageExpectedLenght = 3;
|
||||
mMessage.length = 3;
|
||||
break;
|
||||
|
||||
case SystemExclusiveStart:
|
||||
case SystemExclusiveEnd:
|
||||
// The message can be any lenght
|
||||
// between 3 and MidiMessage::sSysExMaxSize bytes
|
||||
mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize;
|
||||
mMessage.length = MidiMessage::sSysExMaxSize;
|
||||
mRunningStatus_RX = InvalidType;
|
||||
mMessage.sysexArray[0] = pendingType;
|
||||
break;
|
||||
|
|
@ -809,7 +847,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
break;
|
||||
}
|
||||
|
||||
if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
|
||||
if (mPendingMessageIndex >= (mMessage.length - 1))
|
||||
{
|
||||
// Reception complete
|
||||
mMessage.type = pendingType;
|
||||
|
|
@ -818,7 +856,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
mMessage.data2 = 0; // Completed new message has 1 data byte
|
||||
|
||||
mPendingMessageIndex = 0;
|
||||
mPendingMessageExpectedLenght = 0;
|
||||
mMessage.length = 0;
|
||||
mMessage.valid = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -909,7 +947,7 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
mPendingMessage[mPendingMessageIndex] = extracted;
|
||||
|
||||
// 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..
|
||||
// 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];
|
||||
|
||||
// Save data2 only if applicable
|
||||
mMessage.data2 = mPendingMessageExpectedLenght == 3 ? mPendingMessage[2] : 0;
|
||||
mMessage.data2 = mMessage.length == 3 ? mPendingMessage[2] : 0;
|
||||
|
||||
// Reset local variables
|
||||
mPendingMessageIndex = 0;
|
||||
mPendingMessageExpectedLenght = 0;
|
||||
mMessage.length = 0;
|
||||
|
||||
mMessage.valid = true;
|
||||
|
||||
|
|
@ -1014,7 +1052,7 @@ template<class Transport, class Settings, class Platform>
|
|||
inline void MidiInterface<Transport, Settings, Platform>::resetInput()
|
||||
{
|
||||
mPendingMessageIndex = 0;
|
||||
mPendingMessageExpectedLenght = 0;
|
||||
mMessage.length = 0;
|
||||
mRunningStatus_RX = InvalidType;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ struct Message
|
|||
*/
|
||||
bool valid;
|
||||
|
||||
/*! Total Length of the message.
|
||||
*/
|
||||
unsigned length;
|
||||
|
||||
inline unsigned getSysExSize() const
|
||||
{
|
||||
const unsigned size = unsigned(data2) << 8 | data1;
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@ private:
|
|||
*/
|
||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||
typedef MIDI_NAMESPACE::serialMIDI<Type> __smt;\
|
||||
typedef MIDI_NAMESPACE::MidiInterface<__smt> __mismt;\
|
||||
typedef MIDI_NAMESPACE::MidiInterface<__smt> TypedMidiInterface;\
|
||||
__smt serialMidi(SerialPort);\
|
||||
__mismt Name((__smt&)serialMidi);
|
||||
TypedMidiInterface Name((__smt&)serialMidi);
|
||||
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||
|
|
|
|||
Loading…
Reference in New Issue