Fix SysEx size callback bug, using template settings instead of preprocessor macros.

This commit is contained in:
Francois Best 2014-06-11 09:09:08 +02:00
parent 1ff874c70d
commit 219340ea96
10 changed files with 225 additions and 190 deletions

View File

@ -4,6 +4,8 @@
// 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()

View File

@ -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);

View File

@ -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.

View File

@ -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(...)

View File

@ -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])
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -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;
}; };

View File

@ -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

View File

@ -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

81
src/midi_Message.h Normal file
View File

@ -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

View File

@ -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