Fix SysEx size callback bug, using template settings instead of preprocessor macros.
This commit is contained in:
parent
1ff874c70d
commit
219340ea96
|
|
@ -1,9 +1,11 @@
|
||||||
#include <MIDI.h>
|
#include <MIDI.h>
|
||||||
|
|
||||||
// Simple tutorial on how to receive and send MIDI messages.
|
// Simple tutorial on how to receive and send MIDI messages.
|
||||||
// Here, when receiving any message on channel 4, the Arduino
|
// Here, when receiving any message on channel 4, the Arduino
|
||||||
// will blink a led and play back a note for 1 second.
|
// will blink a led and play back a note for 1 second.
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
#define LED 13 // LED pin on Arduino Uno
|
#define LED 13 // LED pin on Arduino Uno
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,39 @@
|
||||||
#include <MIDI.h>
|
#include <MIDI.h>
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// This function will be automatically called when a NoteOn is received.
|
// This function will be automatically called when a NoteOn is received.
|
||||||
// It must be a void-returning function with the correct parameters,
|
// It must be a void-returning function with the correct parameters,
|
||||||
// see documentation here:
|
// see documentation here:
|
||||||
// http://arduinomidilib.fortyseveneffects.com/a00022.html
|
// http://arduinomidilib.fortyseveneffects.com/a00022.html
|
||||||
|
|
||||||
void HandleNoteOn(byte channel, byte pitch, byte velocity)
|
void handleNoteOn(byte channel, byte pitch, byte velocity)
|
||||||
{
|
{
|
||||||
// Do whatever you want when you receive a Note On.
|
// Do whatever you want when a note is pressed.
|
||||||
|
|
||||||
if (velocity == 0)
|
|
||||||
{
|
|
||||||
// This acts like a NoteOff. You can ask the library to call the NoteOff
|
|
||||||
// callback when receiving null-velocity NoteOn messages.
|
|
||||||
// See MIDI_HANDLE_NULL_VELOCITY_NOTE_ON_AS_NOTE_OFF in midi_Settings.h
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to keep your callbacks short (no delays ect)
|
// Try to keep your callbacks short (no delays ect)
|
||||||
// otherwise it would slow down the loop() and have a bad impact
|
// otherwise it would slow down the loop() and have a bad impact
|
||||||
// on real-time performance.
|
// on real-time performance.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleNoteOff(byte channel, byte pitch, byte velocity)
|
||||||
|
{
|
||||||
|
// Do something when the note is released.
|
||||||
|
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
// Connect the HandleNoteOn function to the library,
|
// Connect the handleNoteOn function to the library,
|
||||||
// so it is called upon reception of a NoteOn.
|
// so it is called upon reception of a NoteOn.
|
||||||
MIDI.setHandleNoteOn(HandleNoteOn); // Put only the name of the function
|
MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function
|
||||||
|
|
||||||
|
// Do the same for NoteOffs
|
||||||
|
MIDI.setHandleNoteOff(handleNoteOff);
|
||||||
|
|
||||||
// Initiate MIDI communications, listen to all channels
|
// Initiate MIDI communications, listen to all channels
|
||||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
#include <MIDI.h>
|
#include <MIDI.h>
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// This example shows the old way of checking for input messages.
|
// This example shows the old way of checking for input messages.
|
||||||
// It's simpler to use the callbacks now, check out the dedicated example.
|
// It's simpler to use the callbacks now, check out the dedicated example.
|
||||||
|
|
||||||
|
|
@ -8,7 +12,7 @@
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
void BlinkLed(byte num) // Basic blink function
|
void BlinkLed(byte num) // Basic blink function
|
||||||
{
|
{
|
||||||
for (byte i=0;i<num;i++)
|
for (byte i=0;i<num;i++)
|
||||||
{
|
{
|
||||||
digitalWrite(LED,HIGH);
|
digitalWrite(LED,HIGH);
|
||||||
|
|
@ -29,12 +33,12 @@ void setup()
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
if (MIDI.read()) // Is there a MIDI message incoming ?
|
if (MIDI.read()) // Is there a MIDI message incoming ?
|
||||||
{
|
{
|
||||||
switch(MIDI.getType()) // Get the type of the message we caught
|
switch(MIDI.getType()) // Get the type of the message we caught
|
||||||
{
|
{
|
||||||
case midi::ProgramChange: // If it is a Program Change,
|
case midi::ProgramChange: // If it is a Program Change,
|
||||||
BlinkLed(MIDI.getData1()); // blink the LED a number of times
|
BlinkLed(MIDI.getData1()); // blink the LED a number of times
|
||||||
// correponding to the program number
|
// correponding to the program number
|
||||||
// (0 to 127, it can last a while..)
|
// (0 to 127, it can last a while..)
|
||||||
break;
|
break;
|
||||||
// See the online reference for other message types
|
// See the online reference for other message types
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#include "noteList.h"
|
#include "noteList.h"
|
||||||
#include "pitches.h"
|
#include "pitches.h"
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
#ifdef ARDUINO_SAM_DUE // Due has no tone function (yet), overriden to prevent build errors.
|
#ifdef ARDUINO_SAM_DUE // Due has no tone function (yet), overriden to prevent build errors.
|
||||||
#define tone(...)
|
#define tone(...)
|
||||||
#define noTone(...)
|
#define noTone(...)
|
||||||
|
|
@ -50,7 +52,7 @@ void handleNotesChanged(bool isFirstNote = false)
|
||||||
if (midiNotes.getLast(currentNote))
|
if (midiNotes.getLast(currentNote))
|
||||||
{
|
{
|
||||||
tone(sAudioOutPin, sNotePitches[currentNote]);
|
tone(sAudioOutPin, sNotePitches[currentNote]);
|
||||||
|
|
||||||
if (isFirstNote)
|
if (isFirstNote)
|
||||||
{
|
{
|
||||||
handleGateChanged(true);
|
handleGateChanged(true);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import argparse
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from midi import *
|
from midi import *
|
||||||
from tester import *
|
from tester import *
|
||||||
|
|
@ -138,28 +139,42 @@ class ArduinoMidiLibrary:
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
midiInterface = MidiInterface()
|
|
||||||
tester = Tester(midiInterface)
|
|
||||||
midiInterface.listenerCallback = tester.handleMidiInput
|
|
||||||
|
|
||||||
tester.checkThru([Midi.NoteOn, 64, 80])
|
info = "Validator script for the Arduino MIDI Library."
|
||||||
tester.checkThru([Midi.AfterTouchChannel, 1])
|
arg_parser = argparse.ArgumentParser(description = info)
|
||||||
tester.checkThru([2])
|
|
||||||
tester.checkThru([3])
|
|
||||||
tester.checkThru([Midi.NoteOn, 64, 0])
|
|
||||||
tester.checkThru([65, 127])
|
|
||||||
tester.checkThru([65, 0])
|
|
||||||
tester.checkThru([66, 127])
|
|
||||||
tester.checkThru([66, 0])
|
|
||||||
|
|
||||||
#lib = ArduinoMidiLibrary()
|
arg_parser.add_argument('--compile', '-c',
|
||||||
#lib.install()
|
action="store_true",
|
||||||
#if lib.validate():
|
help="Test compilation of the example sketches")
|
||||||
# print('Validation passed')
|
|
||||||
#else:
|
|
||||||
# print('Validation failed')
|
|
||||||
|
|
||||||
|
arg_parser.add_argument('--runtime', '-r',
|
||||||
|
action="store_true",
|
||||||
|
help="Test runtime")
|
||||||
|
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
if args.compile:
|
||||||
|
lib = ArduinoMidiLibrary()
|
||||||
|
lib.install()
|
||||||
|
if lib.validate():
|
||||||
|
print('Compilation test passed')
|
||||||
|
else:
|
||||||
|
print('Compilation test failed')
|
||||||
|
|
||||||
|
if args.runtime:
|
||||||
|
midiInterface = MidiInterface()
|
||||||
|
tester = Tester(midiInterface)
|
||||||
|
midiInterface.listenerCallback = tester.handleMidiInput
|
||||||
|
|
||||||
|
tester.checkThru([Midi.NoteOn, 64, 80])
|
||||||
|
tester.checkThru([Midi.AfterTouchChannel, 1])
|
||||||
|
tester.checkThru([2])
|
||||||
|
tester.checkThru([3])
|
||||||
|
tester.checkThru([Midi.NoteOn, 64, 0])
|
||||||
|
tester.checkThru([65, 127])
|
||||||
|
tester.checkThru([65, 0])
|
||||||
|
tester.checkThru([66, 127])
|
||||||
|
tester.checkThru([66, 0])
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
20
src/MIDI.h
20
src/MIDI.h
|
|
@ -23,8 +23,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "midi_Settings.h"
|
|
||||||
#include "midi_Defs.h"
|
#include "midi_Defs.h"
|
||||||
|
#include "midi_Settings.h"
|
||||||
|
#include "midi_Message.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -131,7 +132,7 @@ public:
|
||||||
inline void setHandleProgramChange(void (*fptr)(byte channel, byte number));
|
inline void setHandleProgramChange(void (*fptr)(byte channel, byte number));
|
||||||
inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
|
inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
|
||||||
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend));
|
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend));
|
||||||
inline void setHandleSystemExclusive(void (*fptr)(byte * array, byte size));
|
inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size));
|
||||||
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
|
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
|
||||||
inline void setHandleSongPosition(void (*fptr)(unsigned beats));
|
inline void setHandleSongPosition(void (*fptr)(unsigned beats));
|
||||||
inline void setHandleSongSelect(void (*fptr)(byte songnumber));
|
inline void setHandleSongSelect(void (*fptr)(byte songnumber));
|
||||||
|
|
@ -155,7 +156,7 @@ private:
|
||||||
void (*mProgramChangeCallback)(byte channel, byte);
|
void (*mProgramChangeCallback)(byte channel, byte);
|
||||||
void (*mAfterTouchChannelCallback)(byte channel, byte);
|
void (*mAfterTouchChannelCallback)(byte channel, byte);
|
||||||
void (*mPitchBendCallback)(byte channel, int);
|
void (*mPitchBendCallback)(byte channel, int);
|
||||||
void (*mSystemExclusiveCallback)(byte * array, byte size);
|
void (*mSystemExclusiveCallback)(byte * array, unsigned size);
|
||||||
void (*mTimeCodeQuarterFrameCallback)(byte data);
|
void (*mTimeCodeQuarterFrameCallback)(byte data);
|
||||||
void (*mSongPositionCallback)(unsigned beats);
|
void (*mSongPositionCallback)(unsigned beats);
|
||||||
void (*mSongSelectCallback)(byte songnumber);
|
void (*mSongSelectCallback)(byte songnumber);
|
||||||
|
|
@ -192,25 +193,22 @@ private:
|
||||||
bool mThruActivated : 1;
|
bool mThruActivated : 1;
|
||||||
MidiFilterMode mThruFilterMode : 7;
|
MidiFilterMode mThruFilterMode : 7;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StatusByte mRunningStatus_RX;
|
StatusByte mRunningStatus_RX;
|
||||||
|
StatusByte mRunningStatus_TX;
|
||||||
Channel mInputChannel;
|
Channel mInputChannel;
|
||||||
byte mPendingMessage[3];
|
byte mPendingMessage[3];
|
||||||
unsigned mPendingMessageExpectedLenght;
|
unsigned mPendingMessageExpectedLenght;
|
||||||
unsigned mPendingMessageIndex;
|
unsigned mPendingMessageIndex;
|
||||||
Message mMessage;
|
MidiMessage mMessage;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline StatusByte getStatus(MidiType inType,
|
inline StatusByte getStatus(MidiType inType,
|
||||||
Channel inChannel) const;
|
Channel inChannel) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MIDI_USE_RUNNING_STATUS
|
|
||||||
private:
|
|
||||||
StatusByte mRunningStatus_TX;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SerialPort& mSerial;
|
SerialPort& mSerial;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
77
src/MIDI.hpp
77
src/MIDI.hpp
|
|
@ -79,18 +79,10 @@ void MidiInterface<SerialPort, Settings>::begin(Channel inChannel)
|
||||||
mSerial.begin(Settings::BaudRate);
|
mSerial.begin(Settings::BaudRate);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MIDI_BUILD_OUTPUT
|
|
||||||
if (Settings::UseRunningStatus)
|
|
||||||
{
|
|
||||||
mRunningStatus_TX = InvalidType;
|
|
||||||
}
|
|
||||||
#endif // MIDI_BUILD_OUTPUT
|
|
||||||
|
|
||||||
|
|
||||||
#if MIDI_BUILD_INPUT
|
|
||||||
|
|
||||||
mInputChannel = inChannel;
|
mInputChannel = inChannel;
|
||||||
|
mRunningStatus_TX = InvalidType;
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
|
|
||||||
mPendingMessageIndex = 0;
|
mPendingMessageIndex = 0;
|
||||||
mPendingMessageExpectedLenght = 0;
|
mPendingMessageExpectedLenght = 0;
|
||||||
|
|
||||||
|
|
@ -100,25 +92,14 @@ void MidiInterface<SerialPort, Settings>::begin(Channel inChannel)
|
||||||
mMessage.data1 = 0;
|
mMessage.data1 = 0;
|
||||||
mMessage.data2 = 0;
|
mMessage.data2 = 0;
|
||||||
|
|
||||||
#endif // MIDI_BUILD_INPUT
|
|
||||||
|
|
||||||
|
|
||||||
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU) // Thru
|
|
||||||
|
|
||||||
mThruFilterMode = Full;
|
mThruFilterMode = Full;
|
||||||
mThruActivated = true;
|
mThruActivated = true;
|
||||||
|
|
||||||
#endif // Thru
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Output
|
// Output
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if MIDI_BUILD_OUTPUT
|
|
||||||
|
|
||||||
/*! \addtogroup output
|
/*! \addtogroup output
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
@ -459,15 +440,10 @@ StatusByte MidiInterface<SerialPort, Settings>::getStatus(MidiType inType,
|
||||||
return ((byte)inType | ((inChannel - 1) & 0x0f));
|
return ((byte)inType | ((inChannel - 1) & 0x0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MIDI_BUILD_OUTPUT
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Input
|
// Input
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if MIDI_BUILD_INPUT
|
|
||||||
|
|
||||||
/*! \addtogroup input
|
/*! \addtogroup input
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
@ -505,9 +481,7 @@ inline bool MidiInterface<SerialPort, Settings>::read(Channel inChannel)
|
||||||
launchCallback();
|
launchCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MIDI_BUILD_THRU
|
|
||||||
thruFilter(inChannel);
|
thruFilter(inChannel);
|
||||||
#endif
|
|
||||||
|
|
||||||
return channelMatch;
|
return channelMatch;
|
||||||
}
|
}
|
||||||
|
|
@ -604,8 +578,8 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
|
|
||||||
case SystemExclusive:
|
case SystemExclusive:
|
||||||
// The message can be any lenght
|
// The message can be any lenght
|
||||||
// between 3 and MIDI_SYSEX_ARRAY_SIZE bytes
|
// between 3 and MidiMessage::sSysExMaxSize bytes
|
||||||
mPendingMessageExpectedLenght = MIDI_SYSEX_ARRAY_SIZE;
|
mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize;
|
||||||
mRunningStatus_RX = InvalidType;
|
mRunningStatus_RX = InvalidType;
|
||||||
mMessage.sysexArray[0] = SystemExclusive;
|
mMessage.sysexArray[0] = SystemExclusive;
|
||||||
break;
|
break;
|
||||||
|
|
@ -693,8 +667,8 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
mMessage.type = SystemExclusive;
|
mMessage.type = SystemExclusive;
|
||||||
|
|
||||||
// Get length
|
// Get length
|
||||||
mMessage.data1 = mPendingMessageIndex & 0xff;
|
mMessage.data1 = mPendingMessageIndex & 0xff; // LSB
|
||||||
mMessage.data2 = mPendingMessageIndex >> 8;
|
mMessage.data2 = mPendingMessageIndex >> 8; // MSB
|
||||||
mMessage.channel = 0;
|
mMessage.channel = 0;
|
||||||
mMessage.valid = true;
|
mMessage.valid = true;
|
||||||
|
|
||||||
|
|
@ -725,7 +699,7 @@ bool MidiInterface<SerialPort, Settings>::parse()
|
||||||
{
|
{
|
||||||
// "FML" case: fall down here with an overflown SysEx..
|
// "FML" case: fall down here with an overflown SysEx..
|
||||||
// This means we received the last possible data byte that can fit
|
// This means we received the last possible data byte that can fit
|
||||||
// the buffer. If this happens, try increasing MIDI_SYSEX_ARRAY_SIZE.
|
// the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize.
|
||||||
if (mPendingMessage[0] == SystemExclusive)
|
if (mPendingMessage[0] == SystemExclusive)
|
||||||
{
|
{
|
||||||
resetInput();
|
resetInput();
|
||||||
|
|
@ -852,7 +826,7 @@ 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 SerialPort, class Settings>
|
||||||
MidiType MidiInterface<SerialPort, Settings>::getType() const
|
inline MidiType MidiInterface<SerialPort, Settings>::getType() const
|
||||||
{
|
{
|
||||||
return mMessage.type;
|
return mMessage.type;
|
||||||
}
|
}
|
||||||
|
|
@ -863,21 +837,21 @@ MidiType MidiInterface<SerialPort, Settings>::getType() const
|
||||||
For non-channel messages, this will return 0.
|
For non-channel messages, this will return 0.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class SerialPort, class Settings>
|
||||||
Channel MidiInterface<SerialPort, Settings>::getChannel() const
|
inline Channel MidiInterface<SerialPort, 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 SerialPort, class Settings>
|
||||||
DataByte MidiInterface<SerialPort, Settings>::getData1() const
|
inline DataByte MidiInterface<SerialPort, 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 SerialPort, class Settings>
|
||||||
DataByte MidiInterface<SerialPort, Settings>::getData2() const
|
inline DataByte MidiInterface<SerialPort, Settings>::getData2() const
|
||||||
{
|
{
|
||||||
return mMessage.data2;
|
return mMessage.data2;
|
||||||
}
|
}
|
||||||
|
|
@ -887,7 +861,7 @@ 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 SerialPort, class Settings>
|
||||||
const byte* MidiInterface<SerialPort, Settings>::getSysExArray() const
|
inline const byte* MidiInterface<SerialPort, Settings>::getSysExArray() const
|
||||||
{
|
{
|
||||||
return mMessage.sysexArray;
|
return mMessage.sysexArray;
|
||||||
}
|
}
|
||||||
|
|
@ -898,16 +872,14 @@ const byte* MidiInterface<SerialPort, Settings>::getSysExArray() const
|
||||||
\return The array's length, in bytes.
|
\return The array's length, in bytes.
|
||||||
*/
|
*/
|
||||||
template<class SerialPort, class Settings>
|
template<class SerialPort, class Settings>
|
||||||
unsigned MidiInterface<SerialPort, Settings>::getSysExArrayLength() const
|
inline unsigned MidiInterface<SerialPort, Settings>::getSysExArrayLength() const
|
||||||
{
|
{
|
||||||
static const unsigned maxSize = Settings::SysExArraySize;
|
return mMessage.getSysExSize();
|
||||||
const unsigned size = (unsigned(mMessage.data2) << 8) | mMessage.data1;
|
|
||||||
return (size > maxSize) ? maxSize : size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \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 SerialPort, class Settings>
|
||||||
bool MidiInterface<SerialPort, Settings>::check() const
|
inline bool MidiInterface<SerialPort, Settings>::check() const
|
||||||
{
|
{
|
||||||
return mMessage.valid;
|
return mMessage.valid;
|
||||||
}
|
}
|
||||||
|
|
@ -915,7 +887,7 @@ bool MidiInterface<SerialPort, Settings>::check() const
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class SerialPort, class Settings>
|
template<class SerialPort, class Settings>
|
||||||
Channel MidiInterface<SerialPort, Settings>::getInputChannel() const
|
inline Channel MidiInterface<SerialPort, Settings>::getInputChannel() const
|
||||||
{
|
{
|
||||||
return mInputChannel;
|
return mInputChannel;
|
||||||
}
|
}
|
||||||
|
|
@ -925,7 +897,7 @@ Channel MidiInterface<SerialPort, Settings>::getInputChannel() const
|
||||||
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 SerialPort, class Settings>
|
||||||
void MidiInterface<SerialPort, Settings>::setInputChannel(Channel inChannel)
|
inline void MidiInterface<SerialPort, Settings>::setInputChannel(Channel inChannel)
|
||||||
{
|
{
|
||||||
mInputChannel = inChannel;
|
mInputChannel = inChannel;
|
||||||
}
|
}
|
||||||
|
|
@ -980,8 +952,6 @@ bool MidiInterface<SerialPort, Settings>::isChannelMessage(MidiType inType)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if MIDI_USE_CALLBACKS
|
|
||||||
|
|
||||||
/*! \addtogroup callbacks
|
/*! \addtogroup callbacks
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
@ -993,7 +963,7 @@ template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settin
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
|
template<class SerialPort, class Settings> void MidiInterface<SerialPort, 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 SerialPort, class Settings> void MidiInterface<SerialPort, 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 SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
|
||||||
template<class SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSystemExclusive(void (*fptr)(byte* array, byte size)) { mSystemExclusiveCallback = fptr; }
|
template<class SerialPort, class Settings> void MidiInterface<SerialPort, 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 SerialPort, class Settings> void MidiInterface<SerialPort, 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 SerialPort, class Settings> void MidiInterface<SerialPort, 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 SerialPort, class Settings> void MidiInterface<SerialPort, Settings>::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
|
||||||
|
|
@ -1066,7 +1036,7 @@ void MidiInterface<SerialPort, Settings>::launchCallback()
|
||||||
case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break;
|
case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break;
|
||||||
|
|
||||||
case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break;
|
case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break;
|
||||||
case SystemExclusive: if (mSystemExclusiveCallback != 0) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.data1); break;
|
case SystemExclusive: if (mSystemExclusiveCallback != 0) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); break;
|
||||||
|
|
||||||
// Occasional messages
|
// Occasional messages
|
||||||
case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break;
|
case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break;
|
||||||
|
|
@ -1081,19 +1051,12 @@ void MidiInterface<SerialPort, Settings>::launchCallback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MIDI_USE_CALLBACKS
|
|
||||||
|
|
||||||
/*! @} */ // End of doc group MIDI Input
|
/*! @} */ // End of doc group MIDI Input
|
||||||
|
|
||||||
#endif // MIDI_BUILD_INPUT
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Thru
|
// Thru
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
|
|
||||||
|
|
||||||
/*! \addtogroup thru
|
/*! \addtogroup thru
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
@ -1238,8 +1201,6 @@ void MidiInterface<SerialPort, Settings>::thruFilter(Channel inChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MIDI_BUILD_THRU
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
END_MIDI_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "midi_Namespace.h"
|
#include "midi_Namespace.h"
|
||||||
#include "midi_Settings.h"
|
|
||||||
|
#if ARDUINO
|
||||||
|
#include <Arduino.h>
|
||||||
|
#else
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
typedef uint8_t byte;
|
||||||
|
#endif
|
||||||
|
|
||||||
BEGIN_MIDI_NAMESPACE
|
BEGIN_MIDI_NAMESPACE
|
||||||
|
|
||||||
|
|
@ -40,7 +45,6 @@ BEGIN_MIDI_NAMESPACE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Type definitions
|
// Type definitions
|
||||||
|
|
||||||
typedef uint8_t byte;
|
|
||||||
typedef byte StatusByte;
|
typedef byte StatusByte;
|
||||||
typedef byte DataByte;
|
typedef byte DataByte;
|
||||||
typedef byte Channel;
|
typedef byte Channel;
|
||||||
|
|
@ -155,48 +159,6 @@ enum MidiControlChangeNumber
|
||||||
PolyModeOn = 127
|
PolyModeOn = 127
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*! The midimsg structure contains decoded data of a MIDI message
|
|
||||||
read from the serial port with read()
|
|
||||||
*/
|
|
||||||
struct Message
|
|
||||||
{
|
|
||||||
/*! The MIDI channel on which the message was recieved.
|
|
||||||
\n Value goes from 1 to 16.
|
|
||||||
*/
|
|
||||||
Channel channel;
|
|
||||||
|
|
||||||
/*! The type of the message
|
|
||||||
(see the MidiType enum for types reference)
|
|
||||||
*/
|
|
||||||
MidiType type;
|
|
||||||
|
|
||||||
/*! The first data byte.
|
|
||||||
\n Value goes from 0 to 127.
|
|
||||||
*/
|
|
||||||
DataByte data1;
|
|
||||||
|
|
||||||
/*! The second data byte.
|
|
||||||
If the message is only 2 bytes long, this one is null.
|
|
||||||
\n Value goes from 0 to 127.
|
|
||||||
*/
|
|
||||||
DataByte data2;
|
|
||||||
|
|
||||||
/*! System Exclusive dedicated byte array.
|
|
||||||
\n Array length is stocked on 16 bits,
|
|
||||||
in data1 (LSB) and data2 (MSB)
|
|
||||||
*/
|
|
||||||
DataByte sysexArray[MIDI_SYSEX_ARRAY_SIZE];
|
|
||||||
|
|
||||||
/*! This boolean indicates if the message is valid or not.
|
|
||||||
There is no channel consideration here,
|
|
||||||
validity means the message respects the MIDI norm.
|
|
||||||
*/
|
|
||||||
bool valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*! \brief Create an instance of the library attached to a serial port.
|
/*! \brief Create an instance of the library attached to a serial port.
|
||||||
|
|
@ -207,6 +169,19 @@ struct Message
|
||||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||||
midi::MidiInterface<Type> Name((Type&)SerialPort);
|
midi::MidiInterface<Type> Name((Type&)SerialPort);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_SAM_DUE) || defined(USBCON)
|
||||||
|
// 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
|
||||||
|
|
||||||
/*! \brief Create an instance of the library attached to a serial port with
|
/*! \brief Create an instance of the library attached to a serial port with
|
||||||
custom settings.
|
custom settings.
|
||||||
@see DefaultSettings
|
@see DefaultSettings
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*!
|
||||||
|
* @file midi_Message.h
|
||||||
|
* Project Arduino MIDI Library
|
||||||
|
* @brief MIDI Library for the Arduino - Message struct definition
|
||||||
|
* @version 4.1
|
||||||
|
* @author Francois Best
|
||||||
|
* @date 11/06/14
|
||||||
|
* @license GPL v3.0 - Copyright Forty Seven Effects 2014
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "midi_Namespace.h"
|
||||||
|
#include "midi_Defs.h"
|
||||||
|
|
||||||
|
BEGIN_MIDI_NAMESPACE
|
||||||
|
|
||||||
|
/*! The Message structure contains decoded data of a MIDI message
|
||||||
|
read from the serial port with read()
|
||||||
|
*/
|
||||||
|
template<unsigned SysExMaxSize>
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
/*! The maximum size for the System Exclusive array.
|
||||||
|
*/
|
||||||
|
static const unsigned sSysExMaxSize = SysExMaxSize;
|
||||||
|
|
||||||
|
/*! The MIDI channel on which the message was recieved.
|
||||||
|
\n Value goes from 1 to 16.
|
||||||
|
*/
|
||||||
|
Channel channel;
|
||||||
|
|
||||||
|
/*! The type of the message
|
||||||
|
(see the MidiType enum for types reference)
|
||||||
|
*/
|
||||||
|
MidiType type;
|
||||||
|
|
||||||
|
/*! The first data byte.
|
||||||
|
\n Value goes from 0 to 127.
|
||||||
|
*/
|
||||||
|
DataByte data1;
|
||||||
|
|
||||||
|
/*! The second data byte.
|
||||||
|
If the message is only 2 bytes long, this one is null.
|
||||||
|
\n Value goes from 0 to 127.
|
||||||
|
*/
|
||||||
|
DataByte data2;
|
||||||
|
|
||||||
|
/*! System Exclusive dedicated byte array.
|
||||||
|
\n Array length is stocked on 16 bits,
|
||||||
|
in data1 (LSB) and data2 (MSB)
|
||||||
|
*/
|
||||||
|
DataByte sysexArray[sSysExMaxSize];
|
||||||
|
|
||||||
|
/*! This boolean indicates if the message is valid or not.
|
||||||
|
There is no channel consideration here,
|
||||||
|
validity means the message respects the MIDI norm.
|
||||||
|
*/
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
inline unsigned getSysExSize() const
|
||||||
|
{
|
||||||
|
const unsigned size = unsigned(data2) << 8 | data1;
|
||||||
|
return size > sSysExMaxSize ? sSysExMaxSize : size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
END_MIDI_NAMESPACE
|
||||||
|
|
@ -23,47 +23,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "midi_Namespace.h"
|
#include "midi_Defs.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Here are a few settings you can change to customize
|
|
||||||
// the library for your own project. You can for example
|
|
||||||
// choose to compile only parts of it so you gain flash
|
|
||||||
// space and optimise the speed of your sketch.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Compilation flags. Set them to 1 to build the associated feature
|
// Compilation flags. Set them to 1 to build the associated feature
|
||||||
// (MIDI in, out, thru), or to 0 to disable the feature and save space.
|
// (MIDI in, out, thru), or to 0 to disable the feature and save space.
|
||||||
// Note that thru can work only if input and output are enabled.
|
// Note that thru can work only if input and output are enabled.
|
||||||
|
|
||||||
#define MIDI_BUILD_INPUT 1
|
#define MIDI_BUILD_INPUT 1
|
||||||
#define MIDI_BUILD_OUTPUT 1
|
#define MIDI_BUILD_OUTPUT 1
|
||||||
#define MIDI_BUILD_THRU 1
|
#define MIDI_BUILD_THRU 1
|
||||||
|
#define MIDI_USE_CALLBACKS 1
|
||||||
#define MIDI_USE_CALLBACKS 1
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Misc. options
|
|
||||||
|
|
||||||
// Running status enables short messages when sending multiple values
|
|
||||||
// of the same type and channel.
|
|
||||||
// Set to 0 if you have troubles controlling your hardware.
|
|
||||||
#define MIDI_USE_RUNNING_STATUS 1
|
|
||||||
|
|
||||||
// NoteOn with 0 velocity should be handled as NoteOf.
|
|
||||||
// Set to 1 to get NoteOff events when receiving null-velocity NoteOn messages.
|
|
||||||
// Set to 0 to get NoteOn events when receiving null-velocity NoteOn messages.
|
|
||||||
#define MIDI_HANDLE_NULL_VELOCITY_NOTE_ON_AS_NOTE_OFF 1
|
|
||||||
|
|
||||||
// Setting this to 1 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
|
|
||||||
// a lot of traffic, but might induce MIDI Thru and treatment latency.
|
|
||||||
#define MIDI_USE_1BYTE_PARSING 1
|
|
||||||
|
|
||||||
#define MIDI_BAUDRATE 31250
|
|
||||||
#define MIDI_SYSEX_ARRAY_SIZE 255 // Maximum size is 65535 bytes.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -82,11 +51,33 @@ BEGIN_MIDI_NAMESPACE
|
||||||
*/
|
*/
|
||||||
struct DefaultSettings
|
struct DefaultSettings
|
||||||
{
|
{
|
||||||
static const bool UseRunningStatus = true;
|
/*! Running status enables short messages when sending multiple values
|
||||||
static const bool HandleNullVelocityNoteOnAsNoteOff = true;
|
of the same type and channel.\n
|
||||||
static const bool Use1ByteParsing = true;
|
Set to 0 if you have troubles controlling your hardware.
|
||||||
static const unsigned BaudRate = 31250;
|
*/
|
||||||
static const unsigned SysExArraySize = 128;
|
static const bool UseRunningStatus = true;
|
||||||
|
|
||||||
|
/* NoteOn with 0 velocity should be handled as NoteOf.\n
|
||||||
|
Set to 1 to get NoteOff events when receiving null-velocity NoteOn messages.\n
|
||||||
|
Set to 0 to get NoteOn events when receiving null-velocity NoteOn messages.
|
||||||
|
*/
|
||||||
|
static const bool HandleNullVelocityNoteOnAsNoteOff = true;
|
||||||
|
|
||||||
|
// Setting this to 1 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
|
||||||
|
// a lot of traffic, but might induce MIDI Thru and treatment latency.
|
||||||
|
static const bool Use1ByteParsing = true;
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
to receive SysEx, or adjust accordingly.
|
||||||
|
*/
|
||||||
|
static const unsigned SysExMaxSize = 128;
|
||||||
};
|
};
|
||||||
|
|
||||||
END_MIDI_NAMESPACE
|
END_MIDI_NAMESPACE
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue