lift and shift of the Serial code into a seperate class, allowing for other serializers
lift and shift of the Serial code into a seperate class, allowing for other serializers as AppleMIDI, USBMIDI, ipMIDI, BLE-MIDI
This commit is contained in:
parent
0d596066b4
commit
fc752bc834
|
|
@ -7,11 +7,8 @@ add_library(midi STATIC
|
||||||
midi_Defs.h
|
midi_Defs.h
|
||||||
midi_Message.h
|
midi_Message.h
|
||||||
midi_Settings.h
|
midi_Settings.h
|
||||||
midi_RingBuffer.h
|
|
||||||
midi_RingBuffer.hpp
|
|
||||||
midi_UsbTransport.h
|
|
||||||
midi_UsbTransport.hpp
|
|
||||||
MIDI.cpp
|
MIDI.cpp
|
||||||
MIDI.hpp
|
MIDI.hpp
|
||||||
MIDI.h
|
MIDI.h
|
||||||
|
serialMIDI.h
|
||||||
)
|
)
|
||||||
|
|
|
||||||
14
src/MIDI.h
14
src/MIDI.h
|
|
@ -31,6 +31,8 @@
|
||||||
#include "midi_Settings.h"
|
#include "midi_Settings.h"
|
||||||
#include "midi_Message.h"
|
#include "midi_Message.h"
|
||||||
|
|
||||||
|
#include "serialMIDI.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
BEGIN_MIDI_NAMESPACE
|
||||||
|
|
@ -41,14 +43,14 @@ the hardware interface, meaning you can use HardwareSerial, SoftwareSerial
|
||||||
or ak47's Uart classes. The only requirement is that the class implements
|
or ak47's Uart classes. The only requirement is that the class implements
|
||||||
the begin, read, write and available methods.
|
the begin, read, write and available methods.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class _Settings = DefaultSettings>
|
template<class Encoder, class _Settings = DefaultSettings>
|
||||||
class MidiInterface
|
class MidiInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef _Settings Settings;
|
typedef _Settings Settings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline MidiInterface(SerialPort& inSerial);
|
inline MidiInterface(Encoder&);
|
||||||
inline ~MidiInterface();
|
inline ~MidiInterface();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -98,7 +100,7 @@ public:
|
||||||
inline void sendSongSelect(DataByte inSongNumber);
|
inline void sendSongSelect(DataByte inSongNumber);
|
||||||
inline void sendTuneRequest();
|
inline void sendTuneRequest();
|
||||||
inline void sendRealTime(MidiType inType);
|
inline void sendRealTime(MidiType inType);
|
||||||
|
|
||||||
inline void beginRpn(unsigned inNumber,
|
inline void beginRpn(unsigned inNumber,
|
||||||
Channel inChannel);
|
Channel inChannel);
|
||||||
inline void sendRpnValue(unsigned inValue,
|
inline void sendRpnValue(unsigned inValue,
|
||||||
|
|
@ -227,7 +229,7 @@ private:
|
||||||
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SerialPort& mSerial;
|
Encoder& mEncoder;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Channel mInputChannel;
|
Channel mInputChannel;
|
||||||
|
|
@ -240,10 +242,10 @@ private:
|
||||||
unsigned mCurrentNrpnNumber;
|
unsigned mCurrentNrpnNumber;
|
||||||
bool mThruActivated : 1;
|
bool mThruActivated : 1;
|
||||||
Thru::Mode mThruFilterMode : 7;
|
Thru::Mode mThruFilterMode : 7;
|
||||||
unsigned long mLastMessageSentTime;
|
|
||||||
bool mSenderActiveSensingActivated;
|
|
||||||
MidiMessage mMessage;
|
MidiMessage mMessage;
|
||||||
|
|
||||||
|
unsigned long mLastMessageSentTime;
|
||||||
|
bool mSenderActiveSensingActivated;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline StatusByte getStatus(MidiType inType,
|
inline StatusByte getStatus(MidiType inType,
|
||||||
|
|
|
||||||
400
src/MIDI.hpp
400
src/MIDI.hpp
|
|
@ -30,9 +30,9 @@
|
||||||
BEGIN_MIDI_NAMESPACE
|
BEGIN_MIDI_NAMESPACE
|
||||||
|
|
||||||
/// \brief Constructor for MidiInterface.
|
/// \brief Constructor for MidiInterface.
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline MidiInterface<SerialPort, Settings>::MidiInterface(SerialPort& inSerial)
|
inline MidiInterface<Encoder, Settings>::MidiInterface(Encoder& inEncoder)
|
||||||
: mSerial(inSerial)
|
: mEncoder(inEncoder)
|
||||||
, mInputChannel(0)
|
, mInputChannel(0)
|
||||||
, mRunningStatus_RX(InvalidType)
|
, mRunningStatus_RX(InvalidType)
|
||||||
, mRunningStatus_TX(InvalidType)
|
, mRunningStatus_TX(InvalidType)
|
||||||
|
|
@ -40,9 +40,9 @@ inline MidiInterface<SerialPort, Settings>::MidiInterface(SerialPort& inSerial)
|
||||||
, mPendingMessageIndex(0)
|
, mPendingMessageIndex(0)
|
||||||
, mCurrentRpnNumber(0xffff)
|
, mCurrentRpnNumber(0xffff)
|
||||||
, mCurrentNrpnNumber(0xffff)
|
, mCurrentNrpnNumber(0xffff)
|
||||||
, mSenderActiveSensingActivated(false)
|
|
||||||
, mLastMessageSentTime(0)
|
, mLastMessageSentTime(0)
|
||||||
, mThruActivated(true)
|
, mSenderActiveSensingActivated(false)
|
||||||
|
, mThruActivated(false)
|
||||||
, mThruFilterMode(Thru::Full)
|
, mThruFilterMode(Thru::Full)
|
||||||
{
|
{
|
||||||
mNoteOffCallback = 0;
|
mNoteOffCallback = 0;
|
||||||
|
|
@ -69,8 +69,8 @@ inline MidiInterface<SerialPort, Settings>::MidiInterface(SerialPort& inSerial)
|
||||||
|
|
||||||
This is not really useful for the Arduino, as it is never called...
|
This is not really useful for the Arduino, as it is never called...
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline MidiInterface<SerialPort, Settings>::~MidiInterface()
|
inline MidiInterface<Encoder, Settings>::~MidiInterface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,15 +82,11 @@ inline MidiInterface<SerialPort, Settings>::~MidiInterface()
|
||||||
- Input channel set to 1 if no value is specified
|
- Input channel set to 1 if no value is specified
|
||||||
- Full thru mirroring
|
- Full thru mirroring
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::begin(Channel inChannel)
|
void MidiInterface<Encoder, Settings>::begin(Channel inChannel)
|
||||||
{
|
{
|
||||||
// Initialise the Serial port
|
// Initialise the Serial port
|
||||||
#if defined(AVR_CAKE)
|
mEncoder.begin();
|
||||||
mSerial. template open<Settings::BaudRate>();
|
|
||||||
#else
|
|
||||||
mSerial.begin(Settings::BaudRate);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mInputChannel = inChannel;
|
mInputChannel = inChannel;
|
||||||
mRunningStatus_TX = InvalidType;
|
mRunningStatus_TX = InvalidType;
|
||||||
|
|
@ -102,17 +98,17 @@ void MidiInterface<SerialPort, Settings>::begin(Channel inChannel)
|
||||||
mCurrentRpnNumber = 0xffff;
|
mCurrentRpnNumber = 0xffff;
|
||||||
mCurrentNrpnNumber = 0xffff;
|
mCurrentNrpnNumber = 0xffff;
|
||||||
|
|
||||||
|
mSenderActiveSensingActivated = Settings::UseSenderActiveSensing;
|
||||||
|
mLastMessageSentTime = millis();
|
||||||
|
|
||||||
mMessage.valid = false;
|
mMessage.valid = false;
|
||||||
mMessage.type = InvalidType;
|
mMessage.type = InvalidType;
|
||||||
mMessage.channel = 0;
|
mMessage.channel = 0;
|
||||||
mMessage.data1 = 0;
|
mMessage.data1 = 0;
|
||||||
mMessage.data2 = 0;
|
mMessage.data2 = 0;
|
||||||
|
|
||||||
mSenderActiveSensingActivated = Settings::UseSenderActiveSensing;
|
|
||||||
mLastMessageSentTime = millis();
|
|
||||||
|
|
||||||
mThruFilterMode = Thru::Full;
|
mThruFilterMode = Thru::Full;
|
||||||
mThruActivated = true;
|
mThruActivated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
@ -134,8 +130,8 @@ void MidiInterface<SerialPort, Settings>::begin(Channel inChannel)
|
||||||
This is an internal method, use it only if you need to send raw data
|
This is an internal method, use it only if you need to send raw data
|
||||||
from your code, at your own risks.
|
from your code, at your own risks.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::send(MidiType inType,
|
void MidiInterface<Encoder, Settings>::send(MidiType inType,
|
||||||
DataByte inData1,
|
DataByte inData1,
|
||||||
DataByte inData2,
|
DataByte inData2,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
|
|
@ -156,26 +152,31 @@ void MidiInterface<SerialPort, Settings>::send(MidiType inType,
|
||||||
|
|
||||||
const StatusByte status = getStatus(inType, inChannel);
|
const StatusByte status = getStatus(inType, inChannel);
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (mEncoder.beginTransmission())
|
||||||
{
|
{
|
||||||
if (mRunningStatus_TX != status)
|
if (Settings::UseRunningStatus)
|
||||||
{
|
{
|
||||||
// New message, memorise and send header
|
if (mRunningStatus_TX != status)
|
||||||
mRunningStatus_TX = status;
|
{
|
||||||
mSerial.write(mRunningStatus_TX);
|
// New message, memorise and send header
|
||||||
|
mRunningStatus_TX = status;
|
||||||
|
mEncoder.write(mRunningStatus_TX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't care about running status, send the status byte.
|
||||||
|
mEncoder.write(status);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Don't care about running status, send the status byte.
|
|
||||||
mSerial.write(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then send data
|
// Then send data
|
||||||
mSerial.write(inData1);
|
mEncoder.write(inData1);
|
||||||
if (inType != ProgramChange && inType != AfterTouchChannel)
|
if (inType != ProgramChange && inType != AfterTouchChannel)
|
||||||
{
|
{
|
||||||
mSerial.write(inData2);
|
mEncoder.write(inData2);
|
||||||
|
}
|
||||||
|
|
||||||
|
mEncoder.endTransmission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inType >= Clock && inType <= SystemReset)
|
else if (inType >= Clock && inType <= SystemReset)
|
||||||
|
|
@ -198,8 +199,8 @@ void MidiInterface<SerialPort, Settings>::send(MidiType inType,
|
||||||
Take a look at the values, names and frequencies of notes here:
|
Take a look at the values, names and frequencies of notes here:
|
||||||
http://www.phys.unsw.edu.au/jw/notes.html
|
http://www.phys.unsw.edu.au/jw/notes.html
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendNoteOn(DataByte inNoteNumber,
|
void MidiInterface<Encoder, Settings>::sendNoteOn(DataByte inNoteNumber,
|
||||||
DataByte inVelocity,
|
DataByte inVelocity,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -217,8 +218,8 @@ void MidiInterface<SerialPort, Settings>::sendNoteOn(DataByte inNoteNumber,
|
||||||
Take a look at the values, names and frequencies of notes here:
|
Take a look at the values, names and frequencies of notes here:
|
||||||
http://www.phys.unsw.edu.au/jw/notes.html
|
http://www.phys.unsw.edu.au/jw/notes.html
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendNoteOff(DataByte inNoteNumber,
|
void MidiInterface<Encoder, Settings>::sendNoteOff(DataByte inNoteNumber,
|
||||||
DataByte inVelocity,
|
DataByte inVelocity,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -229,8 +230,8 @@ void MidiInterface<SerialPort, Settings>::sendNoteOff(DataByte inNoteNumber,
|
||||||
\param inProgramNumber The Program to select (0 to 127).
|
\param inProgramNumber The Program to select (0 to 127).
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendProgramChange(DataByte inProgramNumber,
|
void MidiInterface<Encoder, Settings>::sendProgramChange(DataByte inProgramNumber,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
send(ProgramChange, inProgramNumber, 0, inChannel);
|
send(ProgramChange, inProgramNumber, 0, inChannel);
|
||||||
|
|
@ -242,8 +243,8 @@ void MidiInterface<SerialPort, Settings>::sendProgramChange(DataByte inProgramNu
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
@see MidiControlChangeNumber
|
@see MidiControlChangeNumber
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendControlChange(DataByte inControlNumber,
|
void MidiInterface<Encoder, Settings>::sendControlChange(DataByte inControlNumber,
|
||||||
DataByte inControlValue,
|
DataByte inControlValue,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -257,8 +258,8 @@ void MidiInterface<SerialPort, Settings>::sendControlChange(DataByte inControlNu
|
||||||
Note: this method is deprecated and will be removed in a future revision of the
|
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.
|
library, @see sendAfterTouch to send polyphonic and monophonic AfterTouch messages.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendPolyPressure(DataByte inNoteNumber,
|
void MidiInterface<Encoder, Settings>::sendPolyPressure(DataByte inNoteNumber,
|
||||||
DataByte inPressure,
|
DataByte inPressure,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -269,8 +270,8 @@ void MidiInterface<SerialPort, Settings>::sendPolyPressure(DataByte inNoteNumber
|
||||||
\param inPressure The amount of AfterTouch to apply to all notes.
|
\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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendAfterTouch(DataByte inPressure,
|
void MidiInterface<Encoder, Settings>::sendAfterTouch(DataByte inPressure,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
send(AfterTouchChannel, inPressure, 0, inChannel);
|
send(AfterTouchChannel, inPressure, 0, inChannel);
|
||||||
|
|
@ -282,8 +283,8 @@ void MidiInterface<SerialPort, Settings>::sendAfterTouch(DataByte inPressure,
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
@see Replaces sendPolyPressure (which is now deprecated).
|
@see Replaces sendPolyPressure (which is now deprecated).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendAfterTouch(DataByte inNoteNumber,
|
void MidiInterface<Encoder, Settings>::sendAfterTouch(DataByte inNoteNumber,
|
||||||
DataByte inPressure,
|
DataByte inPressure,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -296,8 +297,8 @@ void MidiInterface<SerialPort, Settings>::sendAfterTouch(DataByte inNoteNumber,
|
||||||
center value is 0.
|
center value is 0.
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendPitchBend(int inPitchValue,
|
void MidiInterface<Encoder, Settings>::sendPitchBend(int inPitchValue,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
const unsigned bend = unsigned(inPitchValue - int(MIDI_PITCHBEND_MIN));
|
const unsigned bend = unsigned(inPitchValue - int(MIDI_PITCHBEND_MIN));
|
||||||
|
|
@ -311,8 +312,8 @@ void MidiInterface<SerialPort, Settings>::sendPitchBend(int inPitchValue,
|
||||||
and +1.0f (max upwards bend), center value is 0.0f.
|
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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendPitchBend(double inPitchValue,
|
void MidiInterface<Encoder, Settings>::sendPitchBend(double inPitchValue,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : MIDI_PITCHBEND_MIN;
|
const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : MIDI_PITCHBEND_MIN;
|
||||||
|
|
@ -329,26 +330,25 @@ void MidiInterface<SerialPort, Settings>::sendPitchBend(double inPitchValue,
|
||||||
default value for ArrayContainsBoundaries is set to 'false' for compatibility
|
default value for ArrayContainsBoundaries is set to 'false' for compatibility
|
||||||
with previous versions of the library.
|
with previous versions of the library.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendSysEx(unsigned inLength,
|
void MidiInterface<Encoder, Settings>::sendSysEx(unsigned inLength,
|
||||||
const byte* inArray,
|
const byte* inArray,
|
||||||
bool inArrayContainsBoundaries)
|
bool inArrayContainsBoundaries)
|
||||||
{
|
{
|
||||||
const bool writeBeginEndBytes = !inArrayContainsBoundaries;
|
const bool writeBeginEndBytes = !inArrayContainsBoundaries;
|
||||||
|
|
||||||
if (writeBeginEndBytes)
|
if (mEncoder.beginTransmission())
|
||||||
{
|
{
|
||||||
mSerial.write(0xf0);
|
if (writeBeginEndBytes)
|
||||||
}
|
mEncoder.write(0xf0);
|
||||||
|
|
||||||
for (unsigned i = 0; i < inLength; ++i)
|
for (unsigned i = 0; i < inLength; ++i)
|
||||||
{
|
mEncoder.write(inArray[i]);
|
||||||
mSerial.write(inArray[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeBeginEndBytes)
|
if (writeBeginEndBytes)
|
||||||
{
|
mEncoder.write(0xf7);
|
||||||
mSerial.write(0xf7);
|
|
||||||
|
mEncoder.endTransmission();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (Settings::UseRunningStatus)
|
||||||
|
|
@ -362,10 +362,14 @@ void MidiInterface<SerialPort, Settings>::sendSysEx(unsigned inLength,
|
||||||
When a MIDI unit receives this message,
|
When a MIDI unit receives this message,
|
||||||
it should tune its oscillators (if equipped with any).
|
it should tune its oscillators (if equipped with any).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendTuneRequest()
|
void MidiInterface<Encoder, Settings>::sendTuneRequest()
|
||||||
{
|
{
|
||||||
mSerial.write(TuneRequest);
|
if (mEncoder.beginTransmission())
|
||||||
|
{
|
||||||
|
mEncoder.write(TuneRequest);
|
||||||
|
mEncoder.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (Settings::UseRunningStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -379,8 +383,8 @@ void MidiInterface<SerialPort, Settings>::sendTuneRequest()
|
||||||
\param inValuesNibble MTC data
|
\param inValuesNibble MTC data
|
||||||
See MIDI Specification for more information.
|
See MIDI Specification for more information.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
void MidiInterface<Encoder, Settings>::sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||||
DataByte inValuesNibble)
|
DataByte inValuesNibble)
|
||||||
{
|
{
|
||||||
const byte data = byte((((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)));
|
const byte data = byte((((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)));
|
||||||
|
|
@ -393,11 +397,15 @@ void MidiInterface<SerialPort, Settings>::sendTimeCodeQuarterFrame(DataByte inTy
|
||||||
\param inData if you want to encode directly the nibbles in your program,
|
\param inData if you want to encode directly the nibbles in your program,
|
||||||
you can send the byte here.
|
you can send the byte here.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendTimeCodeQuarterFrame(DataByte inData)
|
void MidiInterface<Encoder, Settings>::sendTimeCodeQuarterFrame(DataByte inData)
|
||||||
{
|
{
|
||||||
mSerial.write((byte)TimeCodeQuarterFrame);
|
if (mEncoder.beginTransmission())
|
||||||
mSerial.write(inData);
|
{
|
||||||
|
mEncoder.write((byte)TimeCodeQuarterFrame);
|
||||||
|
mEncoder.write(inData);
|
||||||
|
mEncoder.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (Settings::UseRunningStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -408,12 +416,16 @@ void MidiInterface<SerialPort, Settings>::sendTimeCodeQuarterFrame(DataByte inDa
|
||||||
/*! \brief Send a Song Position Pointer message.
|
/*! \brief Send a Song Position Pointer message.
|
||||||
\param inBeats The number of beats since the start of the song.
|
\param inBeats The number of beats since the start of the song.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendSongPosition(unsigned inBeats)
|
void MidiInterface<Encoder, Settings>::sendSongPosition(unsigned inBeats)
|
||||||
{
|
{
|
||||||
mSerial.write((byte)SongPosition);
|
if (mEncoder.beginTransmission())
|
||||||
mSerial.write(inBeats & 0x7f);
|
{
|
||||||
mSerial.write((inBeats >> 7) & 0x7f);
|
mEncoder.write((byte)SongPosition);
|
||||||
|
mEncoder.write(inBeats & 0x7f);
|
||||||
|
mEncoder.write((inBeats >> 7) & 0x7f);
|
||||||
|
mEncoder.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (Settings::UseRunningStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -422,11 +434,15 @@ void MidiInterface<SerialPort, Settings>::sendSongPosition(unsigned inBeats)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Send a Song Select message */
|
/*! \brief Send a Song Select message */
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendSongSelect(DataByte inSongNumber)
|
void MidiInterface<Encoder, Settings>::sendSongSelect(DataByte inSongNumber)
|
||||||
{
|
{
|
||||||
mSerial.write((byte)SongSelect);
|
if (mEncoder.beginTransmission())
|
||||||
mSerial.write(inSongNumber & 0x7f);
|
{
|
||||||
|
mEncoder.write((byte)SongSelect);
|
||||||
|
mEncoder.write(inSongNumber & 0x7f);
|
||||||
|
mEncoder.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::UseRunningStatus)
|
if (Settings::UseRunningStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -440,8 +456,8 @@ void MidiInterface<SerialPort, Settings>::sendSongSelect(DataByte inSongNumber)
|
||||||
Start, Stop, Continue, Clock, ActiveSensing and SystemReset.
|
Start, Stop, Continue, Clock, ActiveSensing and SystemReset.
|
||||||
@see MidiType
|
@see MidiType
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::sendRealTime(MidiType inType)
|
void MidiInterface<Encoder, Settings>::sendRealTime(MidiType inType)
|
||||||
{
|
{
|
||||||
// Do not invalidate Running Status for real-time messages
|
// Do not invalidate Running Status for real-time messages
|
||||||
// as they can be interleaved within any message.
|
// as they can be interleaved within any message.
|
||||||
|
|
@ -454,7 +470,11 @@ void MidiInterface<SerialPort, Settings>::sendRealTime(MidiType inType)
|
||||||
case Continue:
|
case Continue:
|
||||||
case ActiveSensing:
|
case ActiveSensing:
|
||||||
case SystemReset:
|
case SystemReset:
|
||||||
mSerial.write((byte)inType);
|
if (mEncoder.beginTransmission())
|
||||||
|
{
|
||||||
|
mEncoder.write((byte)inType);
|
||||||
|
mEncoder.endTransmission();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Invalid Real Time marker
|
// Invalid Real Time marker
|
||||||
|
|
@ -466,8 +486,8 @@ void MidiInterface<SerialPort, Settings>::sendRealTime(MidiType inType)
|
||||||
\param inNumber The 14-bit number of the RPN you want to select.
|
\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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::beginRpn(unsigned inNumber,
|
inline void MidiInterface<Encoder, Settings>::beginRpn(unsigned inNumber,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
if (mCurrentRpnNumber != inNumber)
|
if (mCurrentRpnNumber != inNumber)
|
||||||
|
|
@ -484,8 +504,8 @@ inline void MidiInterface<SerialPort, Settings>::beginRpn(unsigned inNumber,
|
||||||
\param inValue The 14-bit value of the selected RPN.
|
\param inValue The 14-bit value of the selected RPN.
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendRpnValue(unsigned inValue,
|
inline void MidiInterface<Encoder, Settings>::sendRpnValue(unsigned inValue,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{;
|
{;
|
||||||
const byte valMsb = 0x7f & (inValue >> 7);
|
const byte valMsb = 0x7f & (inValue >> 7);
|
||||||
|
|
@ -499,8 +519,8 @@ inline void MidiInterface<SerialPort, Settings>::sendRpnValue(unsigned inValue,
|
||||||
\param inLsb The LSB part of the value to send. Meaning depends on RPN number.
|
\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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendRpnValue(byte inMsb,
|
inline void MidiInterface<Encoder, Settings>::sendRpnValue(byte inMsb,
|
||||||
byte inLsb,
|
byte inLsb,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -511,8 +531,8 @@ inline void MidiInterface<SerialPort, Settings>::sendRpnValue(byte inMsb,
|
||||||
/* \brief Increment the value of the currently selected RPN number by the specified amount.
|
/* \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.
|
\param inAmount The amount to add to the currently selected RPN value.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendRpnIncrement(byte inAmount,
|
inline void MidiInterface<Encoder, Settings>::sendRpnIncrement(byte inAmount,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(DataIncrement, inAmount, inChannel);
|
sendControlChange(DataIncrement, inAmount, inChannel);
|
||||||
|
|
@ -521,8 +541,8 @@ inline void MidiInterface<SerialPort, Settings>::sendRpnIncrement(byte inAmount,
|
||||||
/* \brief Decrement the value of the currently selected RPN number by the specified amount.
|
/* \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.
|
\param inAmount The amount to subtract to the currently selected RPN value.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendRpnDecrement(byte inAmount,
|
inline void MidiInterface<Encoder, Settings>::sendRpnDecrement(byte inAmount,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(DataDecrement, inAmount, inChannel);
|
sendControlChange(DataDecrement, inAmount, inChannel);
|
||||||
|
|
@ -532,8 +552,8 @@ inline void MidiInterface<SerialPort, Settings>::sendRpnDecrement(byte inAmount,
|
||||||
This will send a Null Function to deselect the currently selected RPN.
|
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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::endRpn(Channel inChannel)
|
inline void MidiInterface<Encoder, Settings>::endRpn(Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(RPNLSB, 0x7f, inChannel);
|
sendControlChange(RPNLSB, 0x7f, inChannel);
|
||||||
sendControlChange(RPNMSB, 0x7f, inChannel);
|
sendControlChange(RPNMSB, 0x7f, inChannel);
|
||||||
|
|
@ -546,8 +566,8 @@ inline void MidiInterface<SerialPort, Settings>::endRpn(Channel inChannel)
|
||||||
\param inNumber The 14-bit number of the NRPN you want to select.
|
\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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::beginNrpn(unsigned inNumber,
|
inline void MidiInterface<Encoder, Settings>::beginNrpn(unsigned inNumber,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
if (mCurrentNrpnNumber != inNumber)
|
if (mCurrentNrpnNumber != inNumber)
|
||||||
|
|
@ -564,8 +584,8 @@ inline void MidiInterface<SerialPort, Settings>::beginNrpn(unsigned inNumber,
|
||||||
\param inValue The 14-bit value of the selected NRPN.
|
\param inValue The 14-bit value of the selected NRPN.
|
||||||
\param inChannel The channel on which the message will be sent (1 to 16).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendNrpnValue(unsigned inValue,
|
inline void MidiInterface<Encoder, Settings>::sendNrpnValue(unsigned inValue,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{;
|
{;
|
||||||
const byte valMsb = 0x7f & (inValue >> 7);
|
const byte valMsb = 0x7f & (inValue >> 7);
|
||||||
|
|
@ -579,8 +599,8 @@ inline void MidiInterface<SerialPort, Settings>::sendNrpnValue(unsigned inValue,
|
||||||
\param inLsb The LSB part of the value to send. Meaning depends on NRPN number.
|
\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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendNrpnValue(byte inMsb,
|
inline void MidiInterface<Encoder, Settings>::sendNrpnValue(byte inMsb,
|
||||||
byte inLsb,
|
byte inLsb,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
|
|
@ -591,8 +611,8 @@ inline void MidiInterface<SerialPort, Settings>::sendNrpnValue(byte inMsb,
|
||||||
/* \brief Increment the value of the currently selected NRPN number by the specified amount.
|
/* \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.
|
\param inAmount The amount to add to the currently selected NRPN value.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendNrpnIncrement(byte inAmount,
|
inline void MidiInterface<Encoder, Settings>::sendNrpnIncrement(byte inAmount,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(DataIncrement, inAmount, inChannel);
|
sendControlChange(DataIncrement, inAmount, inChannel);
|
||||||
|
|
@ -601,8 +621,8 @@ inline void MidiInterface<SerialPort, Settings>::sendNrpnIncrement(byte inAmount
|
||||||
/* \brief Decrement the value of the currently selected NRPN number by the specified amount.
|
/* \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.
|
\param inAmount The amount to subtract to the currently selected NRPN value.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::sendNrpnDecrement(byte inAmount,
|
inline void MidiInterface<Encoder, Settings>::sendNrpnDecrement(byte inAmount,
|
||||||
Channel inChannel)
|
Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(DataDecrement, inAmount, inChannel);
|
sendControlChange(DataDecrement, inAmount, inChannel);
|
||||||
|
|
@ -612,8 +632,8 @@ inline void MidiInterface<SerialPort, Settings>::sendNrpnDecrement(byte inAmount
|
||||||
This will send a Null Function to deselect the currently selected NRPN.
|
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).
|
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::endNrpn(Channel inChannel)
|
inline void MidiInterface<Encoder, Settings>::endNrpn(Channel inChannel)
|
||||||
{
|
{
|
||||||
sendControlChange(NRPNLSB, 0x7f, inChannel);
|
sendControlChange(NRPNLSB, 0x7f, inChannel);
|
||||||
sendControlChange(NRPNMSB, 0x7f, inChannel);
|
sendControlChange(NRPNMSB, 0x7f, inChannel);
|
||||||
|
|
@ -624,8 +644,8 @@ inline void MidiInterface<SerialPort, Settings>::endNrpn(Channel inChannel)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
StatusByte MidiInterface<SerialPort, Settings>::getStatus(MidiType inType,
|
StatusByte MidiInterface<Encoder, Settings>::getStatus(MidiType inType,
|
||||||
Channel inChannel) const
|
Channel inChannel) const
|
||||||
{
|
{
|
||||||
return StatusByte(((byte)inType | ((inChannel - 1) & 0x0f)));
|
return StatusByte(((byte)inType | ((inChannel - 1) & 0x0f)));
|
||||||
|
|
@ -647,16 +667,16 @@ StatusByte MidiInterface<SerialPort, Settings>::getStatus(MidiType inType,
|
||||||
it is sent back on the MIDI output.
|
it is sent back on the MIDI output.
|
||||||
@see see setInputChannel()
|
@see see setInputChannel()
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline bool MidiInterface<SerialPort, Settings>::read()
|
inline bool MidiInterface<Encoder, Settings>::read()
|
||||||
{
|
{
|
||||||
return read(mInputChannel);
|
return read(mInputChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Read messages on a specified channel.
|
/*! \brief Read messages on a specified channel.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline bool MidiInterface<SerialPort, Settings>::read(Channel inChannel)
|
inline bool MidiInterface<Encoder, Settings>::read(Channel inChannel)
|
||||||
{
|
{
|
||||||
// Active Sensing. This message is intended to be sent
|
// Active Sensing. This message is intended to be sent
|
||||||
// repeatedly to tell the receiver that a connection is alive. Use
|
// repeatedly to tell the receiver that a connection is alive. Use
|
||||||
|
|
@ -666,12 +686,12 @@ inline bool MidiInterface<SerialPort, Settings>::read(Channel inChannel)
|
||||||
// assume that the connection has been terminated. At
|
// assume that the connection has been terminated. At
|
||||||
// termination, the receiver will turn off all voices and return to
|
// termination, the receiver will turn off all voices and return to
|
||||||
// normal (non- active sensing) operation.
|
// normal (non- active sensing) operation.
|
||||||
if (mSenderActiveSensingActivated && (millis() - mLastMessageSentTime) > 250)
|
if (mSenderActiveSensingActivated && (millis() - mLastMessageSentTime) > 270)
|
||||||
{
|
{
|
||||||
sendRealTime(ActiveSensing);
|
sendRealTime(ActiveSensing);
|
||||||
mLastMessageSentTime = millis();
|
mLastMessageSentTime = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inChannel >= MIDI_CHANNEL_OFF)
|
if (inChannel >= MIDI_CHANNEL_OFF)
|
||||||
return false; // MIDI Input disabled.
|
return false; // MIDI Input disabled.
|
||||||
|
|
||||||
|
|
@ -694,10 +714,10 @@ inline bool MidiInterface<SerialPort, Settings>::read(Channel inChannel)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Private method: MIDI parser
|
// Private method: MIDI parser
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
bool MidiInterface<SerialPort, Settings>::parse()
|
bool MidiInterface<Encoder, Settings>::parse()
|
||||||
{
|
{
|
||||||
if (mSerial.available() == 0)
|
if (mEncoder.available() == 0)
|
||||||
{
|
{
|
||||||
// No data available.
|
// No data available.
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -712,7 +732,7 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
// Else, add the extracted byte to the pending message, and check validity.
|
// Else, add the extracted byte to the pending message, and check validity.
|
||||||
// When the message is done, store it.
|
// When the message is done, store it.
|
||||||
|
|
||||||
const byte extracted = mSerial.read();
|
const byte extracted = mEncoder.read();
|
||||||
|
|
||||||
// Ignore Undefined
|
// Ignore Undefined
|
||||||
if (extracted == 0xf9 || extracted == 0xfd)
|
if (extracted == 0xf9 || extracted == 0xfd)
|
||||||
|
|
@ -803,7 +823,7 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
mMessage.sysexArray[0] = pendingType;
|
mMessage.sysexArray[0] = pendingType;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InvalidType:
|
case InvalidType:
|
||||||
default:
|
default:
|
||||||
// This is obviously wrong. Let's get the hell out'a here.
|
// This is obviously wrong. Let's get the hell out'a here.
|
||||||
|
|
@ -873,7 +893,7 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
mMessage.valid = true;
|
mMessage.valid = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// End of Exclusive
|
// Exclusive
|
||||||
case SystemExclusiveStart:
|
case SystemExclusiveStart:
|
||||||
case SystemExclusiveEnd:
|
case SystemExclusiveEnd:
|
||||||
if ((mMessage.sysexArray[0] == SystemExclusiveStart)
|
if ((mMessage.sysexArray[0] == SystemExclusiveStart)
|
||||||
|
|
@ -982,8 +1002,8 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private method, see midi_Settings.h for documentation
|
// Private method, see midi_Settings.h for documentation
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::handleNullVelocityNoteOnAsNoteOff()
|
inline void MidiInterface<Encoder, Settings>::handleNullVelocityNoteOnAsNoteOff()
|
||||||
{
|
{
|
||||||
if (Settings::HandleNullVelocityNoteOnAsNoteOff &&
|
if (Settings::HandleNullVelocityNoteOnAsNoteOff &&
|
||||||
getType() == NoteOn && getData2() == 0)
|
getType() == NoteOn && getData2() == 0)
|
||||||
|
|
@ -993,8 +1013,8 @@ inline void MidiInterface<SerialPort, Settings>::handleNullVelocityNoteOnAsNoteO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private method: check if the received message is on the listened channel
|
// Private method: check if the received message is on the listened channel
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline bool MidiInterface<SerialPort, Settings>::inputFilter(Channel inChannel)
|
inline bool MidiInterface<Encoder, Settings>::inputFilter(Channel inChannel)
|
||||||
{
|
{
|
||||||
// This method handles recognition of channel
|
// This method handles recognition of channel
|
||||||
// (to know if the message is destinated to the Arduino)
|
// (to know if the message is destinated to the Arduino)
|
||||||
|
|
@ -1022,8 +1042,8 @@ inline bool MidiInterface<SerialPort, Settings>::inputFilter(Channel inChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private method: reset input attributes
|
// Private method: reset input attributes
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::resetInput()
|
inline void MidiInterface<Encoder, Settings>::resetInput()
|
||||||
{
|
{
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
mPendingMessageExpectedLenght = 0;
|
||||||
|
|
@ -1036,8 +1056,8 @@ inline void MidiInterface<SerialPort, Settings>::resetInput()
|
||||||
|
|
||||||
Returns an enumerated type. @see MidiType
|
Returns an enumerated type. @see MidiType
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline MidiType MidiInterface<SerialPort, Settings>::getType() const
|
inline MidiType MidiInterface<Encoder, Settings>::getType() const
|
||||||
{
|
{
|
||||||
return mMessage.type;
|
return mMessage.type;
|
||||||
}
|
}
|
||||||
|
|
@ -1047,22 +1067,22 @@ inline MidiType MidiInterface<SerialPort, Settings>::getType() const
|
||||||
\return Channel range is 1 to 16.
|
\return Channel range is 1 to 16.
|
||||||
For non-channel messages, this will return 0.
|
For non-channel messages, this will return 0.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline Channel MidiInterface<SerialPort, Settings>::getChannel() const
|
inline Channel MidiInterface<Encoder, Settings>::getChannel() const
|
||||||
{
|
{
|
||||||
return mMessage.channel;
|
return mMessage.channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Get the first data byte of the last received message. */
|
/*! \brief Get the first data byte of the last received message. */
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline DataByte MidiInterface<SerialPort, Settings>::getData1() const
|
inline DataByte MidiInterface<Encoder, Settings>::getData1() const
|
||||||
{
|
{
|
||||||
return mMessage.data1;
|
return mMessage.data1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Get the second data byte of the last received message. */
|
/*! \brief Get the second data byte of the last received message. */
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline DataByte MidiInterface<SerialPort, Settings>::getData2() const
|
inline DataByte MidiInterface<Encoder, Settings>::getData2() const
|
||||||
{
|
{
|
||||||
return mMessage.data2;
|
return mMessage.data2;
|
||||||
}
|
}
|
||||||
|
|
@ -1071,8 +1091,8 @@ inline DataByte MidiInterface<SerialPort, Settings>::getData2() const
|
||||||
|
|
||||||
@see getSysExArrayLength to get the array's length in bytes.
|
@see getSysExArrayLength to get the array's length in bytes.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline const byte* MidiInterface<SerialPort, Settings>::getSysExArray() const
|
inline const byte* MidiInterface<Encoder, Settings>::getSysExArray() const
|
||||||
{
|
{
|
||||||
return mMessage.sysexArray;
|
return mMessage.sysexArray;
|
||||||
}
|
}
|
||||||
|
|
@ -1082,23 +1102,23 @@ inline const byte* MidiInterface<SerialPort, Settings>::getSysExArray() const
|
||||||
It is coded using data1 as LSB and data2 as MSB.
|
It is coded using data1 as LSB and data2 as MSB.
|
||||||
\return The array's length, in bytes.
|
\return The array's length, in bytes.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline unsigned MidiInterface<SerialPort, Settings>::getSysExArrayLength() const
|
inline unsigned MidiInterface<Encoder, Settings>::getSysExArrayLength() const
|
||||||
{
|
{
|
||||||
return mMessage.getSysExSize();
|
return mMessage.getSysExSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Check if a valid message is stored in the structure. */
|
/*! \brief Check if a valid message is stored in the structure. */
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline bool MidiInterface<SerialPort, Settings>::check() const
|
inline bool MidiInterface<Encoder, Settings>::check() const
|
||||||
{
|
{
|
||||||
return mMessage.valid;
|
return mMessage.valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline Channel MidiInterface<SerialPort, Settings>::getInputChannel() const
|
inline Channel MidiInterface<Encoder, Settings>::getInputChannel() const
|
||||||
{
|
{
|
||||||
return mInputChannel;
|
return mInputChannel;
|
||||||
}
|
}
|
||||||
|
|
@ -1107,8 +1127,8 @@ inline Channel MidiInterface<SerialPort, Settings>::getInputChannel() const
|
||||||
\param inChannel the channel value. Valid values are 1 to 16, MIDI_CHANNEL_OMNI
|
\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.
|
if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::setInputChannel(Channel inChannel)
|
inline void MidiInterface<Encoder, Settings>::setInputChannel(Channel inChannel)
|
||||||
{
|
{
|
||||||
mInputChannel = inChannel;
|
mInputChannel = inChannel;
|
||||||
}
|
}
|
||||||
|
|
@ -1120,8 +1140,8 @@ inline void MidiInterface<SerialPort, Settings>::setInputChannel(Channel inChann
|
||||||
This is a utility static method, used internally,
|
This is a utility static method, used internally,
|
||||||
made public so you can handle MidiTypes more easily.
|
made public so you can handle MidiTypes more easily.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
MidiType MidiInterface<SerialPort, Settings>::getTypeFromStatusByte(byte inStatus)
|
MidiType MidiInterface<Encoder, Settings>::getTypeFromStatusByte(byte inStatus)
|
||||||
{
|
{
|
||||||
if ((inStatus < 0x80) ||
|
if ((inStatus < 0x80) ||
|
||||||
(inStatus == 0xf4) ||
|
(inStatus == 0xf4) ||
|
||||||
|
|
@ -1143,14 +1163,14 @@ MidiType MidiInterface<SerialPort, Settings>::getTypeFromStatusByte(byte inStatu
|
||||||
|
|
||||||
/*! \brief Returns channel in the range 1-16
|
/*! \brief Returns channel in the range 1-16
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline Channel MidiInterface<SerialPort, Settings>::getChannelFromStatusByte(byte inStatus)
|
inline Channel MidiInterface<Encoder, Settings>::getChannelFromStatusByte(byte inStatus)
|
||||||
{
|
{
|
||||||
return Channel((inStatus & 0x0f) + 1);
|
return Channel((inStatus & 0x0f) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
bool MidiInterface<SerialPort, Settings>::isChannelMessage(MidiType inType)
|
bool MidiInterface<Encoder, Settings>::isChannelMessage(MidiType inType)
|
||||||
{
|
{
|
||||||
return (inType == NoteOff ||
|
return (inType == NoteOff ||
|
||||||
inType == NoteOn ||
|
inType == NoteOn ||
|
||||||
|
|
@ -1167,24 +1187,24 @@ bool MidiInterface<SerialPort, Settings>::isChannelMessage(MidiType inType)
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSystemExclusive(void (*fptr)(byte* array, unsigned size)) { mSystemExclusiveCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleSystemExclusive(void (*fptr)(byte* array, unsigned size)) { mSystemExclusiveCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; }
|
template<class Encoder, class Settings> void MidiInterface<Encoder, Settings>::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; }
|
||||||
|
|
||||||
/*! \brief Detach an external function from the given type.
|
/*! \brief Detach an external function from the given type.
|
||||||
|
|
||||||
|
|
@ -1192,8 +1212,8 @@ template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settin
|
||||||
\param inType The type of message to unbind.
|
\param inType The type of message to unbind.
|
||||||
When a message of this type is received, no function will be called.
|
When a message of this type is received, no function will be called.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::disconnectCallbackFromType(MidiType inType)
|
void MidiInterface<Encoder, Settings>::disconnectCallbackFromType(MidiType inType)
|
||||||
{
|
{
|
||||||
switch (inType)
|
switch (inType)
|
||||||
{
|
{
|
||||||
|
|
@ -1223,8 +1243,8 @@ void MidiInterface<SerialPort, Settings>::disconnectCallbackFromType(MidiType in
|
||||||
/*! @} */ // End of doc group MIDI Callbacks
|
/*! @} */ // End of doc group MIDI Callbacks
|
||||||
|
|
||||||
// Private - launch callback function based on received type.
|
// Private - launch callback function based on received type.
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::launchCallback()
|
void MidiInterface<Encoder, Settings>::launchCallback()
|
||||||
{
|
{
|
||||||
// The order is mixed to allow frequent messages to trigger their callback faster.
|
// The order is mixed to allow frequent messages to trigger their callback faster.
|
||||||
switch (mMessage.type)
|
switch (mMessage.type)
|
||||||
|
|
@ -1242,7 +1262,7 @@ void MidiInterface<SerialPort, Settings>::launchCallback()
|
||||||
|
|
||||||
// Continuous controllers
|
// Continuous controllers
|
||||||
case ControlChange: if (mControlChangeCallback != 0) mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2); break;
|
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 PitchBend: if (mPitchBendCallback != 0) mPitchBendCallback(mMessage.channel, (int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN); break;
|
||||||
case AfterTouchPoly: if (mAfterTouchPolyCallback != 0) mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2); break;
|
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 AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break;
|
||||||
|
|
||||||
|
|
@ -1278,34 +1298,34 @@ void MidiInterface<SerialPort, Settings>::launchCallback()
|
||||||
|
|
||||||
@see Thru::Mode
|
@see Thru::Mode
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::setThruFilterMode(Thru::Mode inThruFilterMode)
|
inline void MidiInterface<Encoder, Settings>::setThruFilterMode(Thru::Mode inThruFilterMode)
|
||||||
{
|
{
|
||||||
mThruFilterMode = inThruFilterMode;
|
mThruFilterMode = inThruFilterMode;
|
||||||
mThruActivated = mThruFilterMode != Thru::Off;
|
mThruActivated = mThruFilterMode != Thru::Off;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline Thru::Mode MidiInterface<SerialPort, Settings>::getFilterMode() const
|
inline Thru::Mode MidiInterface<Encoder, Settings>::getFilterMode() const
|
||||||
{
|
{
|
||||||
return mThruFilterMode;
|
return mThruFilterMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline bool MidiInterface<SerialPort, Settings>::getThruState() const
|
inline bool MidiInterface<Encoder, Settings>::getThruState() const
|
||||||
{
|
{
|
||||||
return mThruActivated;
|
return mThruActivated;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::turnThruOn(Thru::Mode inThruFilterMode)
|
inline void MidiInterface<Encoder, Settings>::turnThruOn(Thru::Mode inThruFilterMode)
|
||||||
{
|
{
|
||||||
mThruActivated = true;
|
mThruActivated = true;
|
||||||
mThruFilterMode = inThruFilterMode;
|
mThruFilterMode = inThruFilterMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
inline void MidiInterface<SerialPort, Settings>::turnThruOff()
|
inline void MidiInterface<Encoder, Settings>::turnThruOff()
|
||||||
{
|
{
|
||||||
mThruActivated = false;
|
mThruActivated = false;
|
||||||
mThruFilterMode = Thru::Off;
|
mThruFilterMode = Thru::Off;
|
||||||
|
|
@ -1319,8 +1339,8 @@ inline void MidiInterface<SerialPort, Settings>::turnThruOff()
|
||||||
// to output unless filter is set to Off.
|
// to output unless filter is set to Off.
|
||||||
// - Channel messages are passed to the output whether their channel
|
// - Channel messages are passed to the output whether their channel
|
||||||
// is matching the input channel and the filter setting
|
// is matching the input channel and the filter setting
|
||||||
template<class SerialPort, class Settings>
|
template<class Encoder, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::thruFilter(Channel inChannel)
|
void MidiInterface<Encoder, Settings>::thruFilter(Channel inChannel)
|
||||||
{
|
{
|
||||||
// If the feature is disabled, don't do anything.
|
// If the feature is disabled, don't do anything.
|
||||||
if (!mThruActivated || (mThruFilterMode == Thru::Off))
|
if (!mThruActivated || (mThruFilterMode == Thru::Off))
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,12 @@ enum MidiType: uint8_t
|
||||||
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
|
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
|
||||||
PitchBend = 0xE0, ///< Pitch Bend
|
PitchBend = 0xE0, ///< Pitch Bend
|
||||||
SystemExclusive = 0xF0, ///< System Exclusive
|
SystemExclusive = 0xF0, ///< System Exclusive
|
||||||
SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start
|
SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start
|
||||||
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
|
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
|
||||||
SongPosition = 0xF2, ///< System Common - Song Position Pointer
|
SongPosition = 0xF2, ///< System Common - Song Position Pointer
|
||||||
SongSelect = 0xF3, ///< System Common - Song Select
|
SongSelect = 0xF3, ///< System Common - Song Select
|
||||||
TuneRequest = 0xF6, ///< System Common - Tune Request
|
TuneRequest = 0xF6, ///< System Common - Tune Request
|
||||||
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
|
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
|
||||||
Clock = 0xF8, ///< System Real Time - Timing Clock
|
Clock = 0xF8, ///< System Real Time - Timing Clock
|
||||||
Start = 0xFA, ///< System Real Time - Start
|
Start = 0xFA, ///< System Real Time - Start
|
||||||
Continue = 0xFB, ///< System Real Time - Continue
|
Continue = 0xFB, ///< System Real Time - Continue
|
||||||
|
|
@ -206,35 +206,4 @@ struct RPN
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*! \brief Create an instance of the library attached to a serial port.
|
|
||||||
You can use HardwareSerial or SoftwareSerial for the serial port.
|
|
||||||
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
|
|
||||||
Then call midi2.begin(), midi2.read() etc..
|
|
||||||
*/
|
|
||||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
|
||||||
midi::MidiInterface<Type> Name((Type&)SerialPort);
|
|
||||||
|
|
||||||
#if defined(SERIAL_PORT_HARDWARE_OPEN)
|
|
||||||
// Use recommended default external serial port.
|
|
||||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
|
||||||
MIDI_CREATE_INSTANCE(HardwareSerial, SERIAL_PORT_HARDWARE_OPEN, MIDI);
|
|
||||||
#else
|
|
||||||
/*! \brief Create an instance of the library with default name, serial port
|
|
||||||
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
|
|
||||||
or if you don't bother using custom names, serial port or settings.
|
|
||||||
*/
|
|
||||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
|
||||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! \brief Create an instance of the library attached to a serial port with
|
|
||||||
custom settings.
|
|
||||||
@see DefaultSettings
|
|
||||||
@see MIDI_CREATE_INSTANCE
|
|
||||||
*/
|
|
||||||
#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \
|
|
||||||
midi::MidiInterface<Type, Settings> Name((Type&)SerialPort);
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
END_MIDI_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct Message
|
||||||
*/
|
*/
|
||||||
inline Message()
|
inline Message()
|
||||||
: channel(0)
|
: channel(0)
|
||||||
, type(midi::InvalidType)
|
, type(MIDI_NAMESPACE::InvalidType)
|
||||||
, data1(0)
|
, data1(0)
|
||||||
, data2(0)
|
, data2(0)
|
||||||
, valid(false)
|
, valid(false)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MIDI_NAMESPACE midi
|
#define MIDI_NAMESPACE midi_v440
|
||||||
#define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE {
|
#define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE {
|
||||||
#define END_MIDI_NAMESPACE }
|
#define END_MIDI_NAMESPACE }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_RingBuffer.h
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for Arduino - Ring Buffer
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 10/10/2016
|
|
||||||
* @license MIT - Copyright (c) 2016 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "midi_Namespace.h"
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
class RingBuffer
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
static const int sMask = Size - 1;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RingBuffer();
|
|
||||||
~RingBuffer();
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline int getLength() const;
|
|
||||||
inline bool isEmpty() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void write(DataType inData);
|
|
||||||
void write(const DataType* inData, int inSize);
|
|
||||||
void pop(int inNumberOfItems = 1);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
public:
|
|
||||||
DataType peek(int inOffset = 0) const;
|
|
||||||
DataType read();
|
|
||||||
void read(DataType* outData, int inSize);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataType mData[Size];
|
|
||||||
int mLength;
|
|
||||||
int mWriteHead;
|
|
||||||
int mReadHead;
|
|
||||||
};
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
#include "midi_RingBuffer.hpp"
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_RingBuffer.hpp
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for Arduino - Ring Buffer
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 10/10/2016
|
|
||||||
* @license MIT - Copyright (c) 2016 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template<int N>
|
|
||||||
struct isPowerOfTwo
|
|
||||||
{
|
|
||||||
static const bool value = N && !(N & (N - 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
RingBuffer<DataType, Size>::RingBuffer()
|
|
||||||
: mLength(0)
|
|
||||||
, mWriteHead(0)
|
|
||||||
, mReadHead(0)
|
|
||||||
{
|
|
||||||
static_assert(isPowerOfTwo<Size>::value, "Size must be a power of two.");
|
|
||||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
RingBuffer<DataType, Size>::~RingBuffer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
inline int RingBuffer<DataType, Size>::getLength() const
|
|
||||||
{
|
|
||||||
return mLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
inline bool RingBuffer<DataType, Size>::isEmpty() const
|
|
||||||
{
|
|
||||||
return mLength == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
void RingBuffer<DataType, Size>::write(DataType inData)
|
|
||||||
{
|
|
||||||
mData[mWriteHead] = inData;
|
|
||||||
mWriteHead = (mWriteHead + 1) & sMask;
|
|
||||||
mLength++;
|
|
||||||
if (mLength > Size) {
|
|
||||||
mLength = Size;
|
|
||||||
mReadHead = (mReadHead + 1) & sMask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
void RingBuffer<DataType, Size>::write(const DataType* inData, int inSize)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < inSize; ++i)
|
|
||||||
{
|
|
||||||
write(inData[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
void RingBuffer<DataType, Size>::pop(int inNumberOfItems)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < inNumberOfItems; ++i)
|
|
||||||
{
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
void RingBuffer<DataType, Size>::clear()
|
|
||||||
{
|
|
||||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
|
||||||
mReadHead = 0;
|
|
||||||
mWriteHead = 0;
|
|
||||||
mLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
DataType RingBuffer<DataType, Size>::peek(int inOffset) const
|
|
||||||
{
|
|
||||||
const int head = (mReadHead + inOffset) & sMask;
|
|
||||||
return mData[head];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
DataType RingBuffer<DataType, Size>::read()
|
|
||||||
{
|
|
||||||
mLength--;
|
|
||||||
if (mLength < 0) {
|
|
||||||
mLength = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const DataType data = mData[mReadHead];
|
|
||||||
mReadHead = (mReadHead + 1) & sMask;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, int Size>
|
|
||||||
void RingBuffer<DataType, Size>::read(DataType* outData, int inSize)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < inSize; ++i)
|
|
||||||
{
|
|
||||||
outData[i] = read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
@ -70,19 +70,13 @@ struct DefaultSettings
|
||||||
termination, the receiver will turn off all voices and return to
|
termination, the receiver will turn off all voices and return to
|
||||||
normal (non- active sensing) operation..
|
normal (non- active sensing) operation..
|
||||||
*/
|
*/
|
||||||
static const bool UseSenderActiveSensing = true;
|
static const bool UseSenderActiveSensing = false;
|
||||||
|
|
||||||
/*! Setting this to true will make MIDI.read parse only one byte of data for each
|
/*! Setting this to true will make MIDI.read parse only one byte of data for each
|
||||||
call when data is available. This can speed up your application if receiving
|
call when data is available. This can speed up your application if receiving
|
||||||
a lot of traffic, but might induce MIDI Thru and treatment latency.
|
a lot of traffic, but might induce MIDI Thru and treatment latency.
|
||||||
*/
|
*/
|
||||||
static const bool Use1ByteParsing = true;
|
static const bool Use1ByteParsing = false;
|
||||||
|
|
||||||
/*! Override the default MIDI baudrate to transmit over USB serial, to
|
|
||||||
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
|
|
||||||
http://projectgus.github.io/hairless-midiserial/
|
|
||||||
*/
|
|
||||||
static const long BaudRate = 31250;
|
|
||||||
|
|
||||||
/*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect
|
/*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect
|
||||||
to receive SysEx, or adjust accordingly.
|
to receive SysEx, or adjust accordingly.
|
||||||
|
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_UsbDefs.h
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for the Arduino - Definitions
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 24/02/11
|
|
||||||
* @license MIT - Copyright (c) 2016 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "midi_Defs.h"
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
struct CodeIndexNumbers
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
reserved = 0x00,
|
|
||||||
misc = reserved,
|
|
||||||
|
|
||||||
cableEvent = 0x01,
|
|
||||||
systemCommon2Bytes = 0x02,
|
|
||||||
systemCommon3Bytes = 0x03,
|
|
||||||
|
|
||||||
sysExStart = 0x04,
|
|
||||||
sysExContinue = sysExStart,
|
|
||||||
|
|
||||||
systemCommon1Byte = 0x05,
|
|
||||||
sysExEnds1Byte = systemCommon1Byte,
|
|
||||||
|
|
||||||
sysExEnds2Bytes = 0x06,
|
|
||||||
sysExEnds3Bytes = 0x07,
|
|
||||||
noteOff = 0x08,
|
|
||||||
noteOn = 0x09,
|
|
||||||
polyPressure = 0x0A,
|
|
||||||
controlChange = 0x0B,
|
|
||||||
programChange = 0x0C,
|
|
||||||
channelPressure = 0x0D,
|
|
||||||
pitchBend = 0x0E,
|
|
||||||
singleByte = 0x0F,
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline byte fromStatus(StatusByte inStatus)
|
|
||||||
{
|
|
||||||
const byte statusWithoutChannel = inStatus & 0xf0;
|
|
||||||
if (statusWithoutChannel >= midi::NoteOff &&
|
|
||||||
statusWithoutChannel <= midi::PitchBend)
|
|
||||||
{
|
|
||||||
// Channel Voice Messages
|
|
||||||
return inStatus >> 4;
|
|
||||||
}
|
|
||||||
switch (inStatus)
|
|
||||||
{
|
|
||||||
// System Real Time Messages
|
|
||||||
case midi::Clock:
|
|
||||||
case midi::Start:
|
|
||||||
case midi::Continue:
|
|
||||||
case midi::Stop:
|
|
||||||
case midi::ActiveSensing:
|
|
||||||
case midi::SystemReset:
|
|
||||||
return CodeIndexNumbers::singleByte;
|
|
||||||
|
|
||||||
// System Exclusive
|
|
||||||
case midi::SystemExclusive:
|
|
||||||
return CodeIndexNumbers::sysExStart;
|
|
||||||
case 0xf7:
|
|
||||||
return CodeIndexNumbers::sysExEnds1Byte;
|
|
||||||
|
|
||||||
// System Common Messages
|
|
||||||
case midi::TimeCodeQuarterFrame:
|
|
||||||
return CodeIndexNumbers::systemCommon2Bytes;
|
|
||||||
case midi::SongPosition:
|
|
||||||
return CodeIndexNumbers::systemCommon3Bytes;
|
|
||||||
case midi::SongSelect:
|
|
||||||
return CodeIndexNumbers::systemCommon2Bytes;
|
|
||||||
case midi::TuneRequest:
|
|
||||||
return CodeIndexNumbers::systemCommon1Byte;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return CodeIndexNumbers::reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline byte getSize(byte inCodeIndexNumber)
|
|
||||||
{
|
|
||||||
switch (inCodeIndexNumber)
|
|
||||||
{
|
|
||||||
case noteOn:
|
|
||||||
case noteOff:
|
|
||||||
case controlChange:
|
|
||||||
case pitchBend:
|
|
||||||
case polyPressure:
|
|
||||||
case systemCommon3Bytes:
|
|
||||||
case sysExEnds3Bytes:
|
|
||||||
case sysExStart:
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
case programChange:
|
|
||||||
case channelPressure:
|
|
||||||
case systemCommon2Bytes:
|
|
||||||
case sysExEnds2Bytes:
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case systemCommon1Byte: // also sysExEnds1Byte
|
|
||||||
case singleByte:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0; // Can be any length (1, 2 or 3).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_UsbPacketInterface.h
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 2018-11-03
|
|
||||||
* @license MIT - Copyright (c) 2018 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "midi_Defs.h"
|
|
||||||
#include "midi_UsbDefs.h"
|
|
||||||
#include <MIDIUSB_Defs.h>
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<typename Buffer>
|
|
||||||
bool composeTxPacket(Buffer& inBuffer, midiEventPacket_t& outPacket);
|
|
||||||
|
|
||||||
template<typename Buffer>
|
|
||||||
void serialiseRxPacket(const midiEventPacket_t& inPacket, Buffer& outBuffer);
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
#include "midi_UsbPacketInterface.hpp"
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_UsbPacketInterface.hpp
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 2018-11-03
|
|
||||||
* @license MIT - Copyright (c) 2018 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<typename Buffer>
|
|
||||||
bool composeTxPacket(Buffer& inBuffer, midiEventPacket_t& outPacket)
|
|
||||||
{
|
|
||||||
if (inBuffer.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const int bufferLength = inBuffer.getLength();
|
|
||||||
const byte status = inBuffer.peek();
|
|
||||||
const byte cin = midi::CodeIndexNumbers::fromStatus(status);
|
|
||||||
const byte messageLength = midi::CodeIndexNumbers::getSize(cin);
|
|
||||||
|
|
||||||
if (status == 0xf0)
|
|
||||||
{
|
|
||||||
// Start of SysEx, check if it can end in one go.
|
|
||||||
if (bufferLength == 2 && inBuffer.peek(1) == 0xf7)
|
|
||||||
{
|
|
||||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds2Bytes;
|
|
||||||
outPacket.byte1 = status;
|
|
||||||
outPacket.byte2 = 0xf7;
|
|
||||||
outPacket.byte3 = 0x00;
|
|
||||||
inBuffer.pop(2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (bufferLength >= 3 && inBuffer.peek(2) == 0xf7)
|
|
||||||
{
|
|
||||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds3Bytes;
|
|
||||||
outPacket.byte1 = status;
|
|
||||||
outPacket.byte2 = inBuffer.peek(1);
|
|
||||||
outPacket.byte3 = 0xf7;
|
|
||||||
inBuffer.pop(3);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((status & 0x80) == 0x00)
|
|
||||||
{
|
|
||||||
// First byte is data, consider it's part of a running SysEx message.
|
|
||||||
// We look for the SysEx end byte in the next 2 bytes
|
|
||||||
// At this point, bufferLength should be 2 or more to continue.
|
|
||||||
if (bufferLength == 1)
|
|
||||||
{
|
|
||||||
return false; // Not enough data
|
|
||||||
}
|
|
||||||
if (bufferLength == 2)
|
|
||||||
{
|
|
||||||
const bool isSysExEnd = inBuffer.peek(1) == 0xf7;
|
|
||||||
if (!isSysExEnd)
|
|
||||||
{
|
|
||||||
return false; // Not enough data (eg: 0x12 0x42)
|
|
||||||
}
|
|
||||||
// eg: 0x42 0xf7
|
|
||||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds2Bytes;
|
|
||||||
outPacket.byte1 = status;
|
|
||||||
outPacket.byte2 = inBuffer.peek(1);
|
|
||||||
outPacket.byte3 = 0x00;
|
|
||||||
inBuffer.pop(2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// bufferLength > 2
|
|
||||||
const byte byte3 = inBuffer.peek(2);
|
|
||||||
outPacket.header = byte3 == 0xf7
|
|
||||||
? midi::CodeIndexNumbers::sysExEnds3Bytes
|
|
||||||
: midi::CodeIndexNumbers::sysExContinue;
|
|
||||||
outPacket.byte1 = status;
|
|
||||||
outPacket.byte2 = inBuffer.peek(1);
|
|
||||||
outPacket.byte3 = byte3;
|
|
||||||
inBuffer.pop(3);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferLength < messageLength) {
|
|
||||||
return false; // Not enough data in the buffer to compose a full packet.
|
|
||||||
}
|
|
||||||
|
|
||||||
outPacket.header = cin;
|
|
||||||
outPacket.byte1 = status;
|
|
||||||
outPacket.byte2 = messageLength >= 2 ? inBuffer.peek(1) : 0x00;
|
|
||||||
outPacket.byte3 = messageLength >= 3 ? inBuffer.peek(2) : 0x00;
|
|
||||||
|
|
||||||
inBuffer.pop(messageLength);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// todo: handle interleaved RealTime messages
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Buffer>
|
|
||||||
void serialiseRxPacket(const midiEventPacket_t& inPacket, Buffer& outBuffer)
|
|
||||||
{
|
|
||||||
const byte cin = inPacket.header & 0x0f;
|
|
||||||
const byte messageLength = midi::CodeIndexNumbers::getSize(cin);
|
|
||||||
switch (messageLength)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
outBuffer.write(inPacket.byte1);
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
outBuffer.write(inPacket.byte1);
|
|
||||||
outBuffer.write(inPacket.byte2);
|
|
||||||
return;
|
|
||||||
case 3:
|
|
||||||
outBuffer.write(inPacket.byte1);
|
|
||||||
outBuffer.write(inPacket.byte2);
|
|
||||||
outBuffer.write(inPacket.byte3);
|
|
||||||
return;
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
// Invalid or ignored messages, don't serialise.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_UsbTransport.h
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 10/10/2016
|
|
||||||
* @license MIT - Copyright (c) 2016 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "midi_Defs.h"
|
|
||||||
#include "midi_RingBuffer.h"
|
|
||||||
#include "midi_UsbPacketInterface.h"
|
|
||||||
#include <MIDIUSB.h>
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<unsigned BuffersSize>
|
|
||||||
class UsbTransport
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline UsbTransport();
|
|
||||||
inline ~UsbTransport();
|
|
||||||
|
|
||||||
public: // Serial / Stream API required for template compatibility
|
|
||||||
inline void begin(unsigned inBaudrate);
|
|
||||||
inline unsigned available();
|
|
||||||
inline byte read();
|
|
||||||
inline void write(byte inData);
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline void pollUsbMidi();
|
|
||||||
inline void recomposeAndSendTxPackets();
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef RingBuffer<byte, BuffersSize> Buffer;
|
|
||||||
Buffer mTxBuffer;
|
|
||||||
Buffer mRxBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
#include "midi_UsbTransport.hpp"
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
/*!
|
|
||||||
* @file midi_UsbTransport.hpp
|
|
||||||
* Project Arduino MIDI Library
|
|
||||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
|
||||||
* @author Francois Best
|
|
||||||
* @date 10/10/2016
|
|
||||||
* @license MIT - Copyright (c) 2016 Francois Best
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline UsbTransport<BufferSize>::UsbTransport()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline UsbTransport<BufferSize>::~UsbTransport()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline void UsbTransport<BufferSize>::begin(unsigned inBaudrate)
|
|
||||||
{
|
|
||||||
mTxBuffer.clear();
|
|
||||||
mRxBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline unsigned UsbTransport<BufferSize>::available()
|
|
||||||
{
|
|
||||||
pollUsbMidi();
|
|
||||||
return mRxBuffer.getLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline byte UsbTransport<BufferSize>::read()
|
|
||||||
{
|
|
||||||
return mRxBuffer.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline void UsbTransport<BufferSize>::write(byte inData)
|
|
||||||
{
|
|
||||||
mTxBuffer.write(inData);
|
|
||||||
recomposeAndSendTxPackets();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline void UsbTransport<BufferSize>::pollUsbMidi()
|
|
||||||
{
|
|
||||||
midiEventPacket_t packet = MidiUSB.read();
|
|
||||||
while (packet.header != 0)
|
|
||||||
{
|
|
||||||
serialiseRxPacket(packet, mRxBuffer);
|
|
||||||
packet = MidiUSB.read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned BufferSize>
|
|
||||||
inline void UsbTransport<BufferSize>::recomposeAndSendTxPackets()
|
|
||||||
{
|
|
||||||
midiEventPacket_t packet;
|
|
||||||
bool sent = false;
|
|
||||||
while (composeTxPacket(mTxBuffer, packet))
|
|
||||||
{
|
|
||||||
MidiUSB.sendMIDI(packet);
|
|
||||||
sent = true;
|
|
||||||
}
|
|
||||||
if (sent)
|
|
||||||
{
|
|
||||||
MidiUSB.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
BEGIN_MIDI_NAMESPACE
|
||||||
|
|
||||||
|
template <class SerialPort>
|
||||||
|
class serialMIDI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
serialMIDI(SerialPort& inSerial)
|
||||||
|
: mSerial(inSerial)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void begin(MIDI_NAMESPACE::Channel inChannel = 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool beginTransmission()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void write(byte byte)
|
||||||
|
{
|
||||||
|
mSerial.write(byte);
|
||||||
|
};
|
||||||
|
|
||||||
|
void endTransmission()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
byte read()
|
||||||
|
{
|
||||||
|
return mSerial.read();
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned available()
|
||||||
|
{
|
||||||
|
return mSerial.available();
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
SerialPort& mSerial;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief Create an instance of the library attached to a serial port.
|
||||||
|
You can use HardwareSerial or SoftwareSerial for the serial port.
|
||||||
|
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
|
||||||
|
Then call midi2.begin(), midi2.read() etc..
|
||||||
|
*/
|
||||||
|
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||||
|
typedef MIDI_NAMESPACE::serialMIDI<Type> __amt;\
|
||||||
|
__amt serialMidi(SerialPort);\
|
||||||
|
MIDI_NAMESPACE::MidiInterface<__amt> Name((__amt&)serialMidi);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||||
|
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||||
|
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||||
|
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
|
||||||
|
#else
|
||||||
|
/*! \brief Create an instance of the library with default name, serial port
|
||||||
|
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
|
||||||
|
or if you don't bother using custom names, serial port or settings.
|
||||||
|
*/
|
||||||
|
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||||
|
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
END_MIDI_NAMESPACE
|
||||||
Loading…
Reference in New Issue