Quake wip.

This commit is contained in:
Francois Best 2012-09-05 18:32:42 +02:00
parent 5a42cb006d
commit 4b8b38aeaf
6 changed files with 395 additions and 525 deletions

View File

@ -2,7 +2,7 @@
* @file MIDI.cpp
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino
* @version 3.2
* @version 4.0
* @author Francois Best
* @date 24/02/11
* license GPL Forty Seven Effects - 2011
@ -12,6 +12,7 @@
#include <stdlib.h>
#include "Arduino.h" // If using an old (pre-1.0) version of Arduino,
// use WConstants.h instead of Arduino.h
#if MIDI_USE_SOFTWARE_SERIAL
// Note: Make sure the following relative path is correct.
@ -26,14 +27,17 @@ SoftwareSerial softSerialClass(MIDI_SOFTSERIAL_RX_PIN,
#endif // MIDI_USE_SOFTWARE_SERIAL
/*! \brief Main instance (the class comes pre-instantiated). */
MIDI_Class MIDI;
#if MIDI_AUTO_INSTANCIATE
midi::MidiInterface MIDI;
#endif
/*! \brief Default constructor for MIDI_Class. */
MIDI_Class::MIDI_Class()
BEGIN_MIDI_NAMESPACE
/*! \brief Default constructor for MidiInterface. */
MidiInterface::MidiInterface()
{
#if COMPILE_MIDI_IN && USE_CALLBACKS
#if MIDI_BUILD_INPUT && USE_CALLBACKS
// Initialise callbacks to NULL pointer
mNoteOffCallback = NULL;
@ -59,11 +63,11 @@ MIDI_Class::MIDI_Class()
}
/*! \brief Default destructor for MIDI_Class.
/*! \brief Default destructor for MidiInterface.
This is not really useful for the Arduino, as it is never called...
*/
MIDI_Class::~MIDI_Class()
MidiInterface::~MidiInterface()
{
}
@ -75,19 +79,19 @@ MIDI_Class::~MIDI_Class()
- Input channel set to 1 if no value is specified
- Full thru mirroring
*/
void MIDI_Class::begin(const byte inChannel)
void MidiInterface::begin(const byte inChannel)
{
// Initialise the Serial port
MIDI_SERIAL_PORT.begin(MIDI_BAUDRATE);
#if COMPILE_MIDI_OUT && USE_RUNNING_STATUS
#if MIDI_BUILD_OUTPUT && MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif // COMPILE_MIDI_OUT && USE_RUNNING_STATUS
#endif // MIDI_BUILD_OUTPUT && MIDI_USE_RUNNING_STATUS
#if COMPILE_MIDI_IN
#if MIDI_BUILD_INPUT
mInputChannel = inChannel;
mRunningStatus_RX = InvalidType;
@ -100,10 +104,10 @@ void MIDI_Class::begin(const byte inChannel)
mMessage.data1 = 0;
mMessage.data2 = 0;
#endif // COMPILE_MIDI_IN
#endif // MIDI_BUILD_INPUT
#if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU) // Thru
mThruFilterMode = Full;
mThruActivated = true;
@ -117,14 +121,7 @@ void MIDI_Class::begin(const byte inChannel)
// MIDI Output
// =============================================================================
#if COMPILE_MIDI_OUT
// Private method for generating a status byte from channel and type
const byte MIDI_Class::genstatus(const kMIDIType inType,
const byte inChannel) const
{
return ((byte)inType | ((inChannel-1) & 0x0F));
}
#if MIDI_BUILD_OUTPUT
/*! \brief Generate and send a MIDI message from the values given.
@ -138,7 +135,7 @@ const byte MIDI_Class::genstatus(const kMIDIType inType,
This is an internal method, use it only if you need to send raw data
from your code, at your own risks.
*/
void MIDI_Class::send(kMIDIType type,
void MidiInterface::send(MidiType type,
byte data1,
byte data2,
byte channel)
@ -149,7 +146,7 @@ void MIDI_Class::send(kMIDIType type,
type < NoteOff)
{
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif
@ -164,7 +161,7 @@ void MIDI_Class::send(kMIDIType type,
byte statusbyte = genstatus(type,channel);
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
// Check Running Status
if (mRunningStatus_TX != statusbyte)
{
@ -198,7 +195,7 @@ void MIDI_Class::send(kMIDIType type,
Take a look at the values, names and frequencies of notes here:
http://www.phys.unsw.edu.au/jw/notes.html
*/
void MIDI_Class::sendNoteOn(byte NoteNumber,
void MidiInterface::sendNoteOn(byte NoteNumber,
byte Velocity,
byte Channel)
{
@ -217,7 +214,7 @@ void MIDI_Class::sendNoteOn(byte NoteNumber,
Take a look at the values, names and frequencies of notes here:
http://www.phys.unsw.edu.au/jw/notes.html
*/
void MIDI_Class::sendNoteOff(byte NoteNumber,
void MidiInterface::sendNoteOff(byte NoteNumber,
byte Velocity,
byte Channel)
{
@ -229,7 +226,7 @@ void MIDI_Class::sendNoteOff(byte NoteNumber,
\param ProgramNumber The Program to select (0 to 127).
\param Channel The channel on which the message will be sent (1 to 16).
*/
void MIDI_Class::sendProgramChange(byte ProgramNumber,
void MidiInterface::sendProgramChange(byte ProgramNumber,
byte Channel)
{
send(ProgramChange,ProgramNumber,0,Channel);
@ -244,7 +241,7 @@ void MIDI_Class::sendProgramChange(byte ProgramNumber,
See the detailed controllers numbers & description here:
http://www.somascape.org/midi/tech/spec.html#ctrlnums
*/
void MIDI_Class::sendControlChange(byte ControlNumber,
void MidiInterface::sendControlChange(byte ControlNumber,
byte ControlValue,
byte Channel)
{
@ -257,7 +254,7 @@ void MIDI_Class::sendControlChange(byte ControlNumber,
\param Pressure The amount of AfterTouch to apply (0 to 127).
\param Channel The channel on which the message will be sent (1 to 16).
*/
void MIDI_Class::sendPolyPressure(byte NoteNumber,
void MidiInterface::sendPolyPressure(byte NoteNumber,
byte Pressure,
byte Channel)
{
@ -269,7 +266,7 @@ void MIDI_Class::sendPolyPressure(byte NoteNumber,
\param Pressure The amount of AfterTouch to apply to all notes.
\param Channel The channel on which the message will be sent (1 to 16).
*/
void MIDI_Class::sendAfterTouch(byte Pressure,
void MidiInterface::sendAfterTouch(byte Pressure,
byte Channel)
{
send(AfterTouchChannel,Pressure,0,Channel);
@ -282,7 +279,7 @@ void MIDI_Class::sendAfterTouch(byte Pressure,
center value is 0.
\param Channel The channel on which the message will be sent (1 to 16).
*/
void MIDI_Class::sendPitchBend(int PitchValue,
void MidiInterface::sendPitchBend(int PitchValue,
byte Channel)
{
const unsigned int bend = PitchValue - MIDI_PITCHBEND_MIN;
@ -296,7 +293,7 @@ void MIDI_Class::sendPitchBend(int PitchValue,
and +1.0f (max upwards bend), center value is 0.0f.
\param Channel The channel on which the message will be sent (1 to 16).
*/
void MIDI_Class::sendPitchBend(double PitchValue,
void MidiInterface::sendPitchBend(double PitchValue,
byte Channel)
{
const int pitchval = PitchValue * MIDI_PITCHBEND_MAX;
@ -313,7 +310,7 @@ void MIDI_Class::sendPitchBend(double PitchValue,
default value for ArrayContainsBoundaries is set to 'false' for compatibility
with previous versions of the library.
*/
void MIDI_Class::sendSysEx(int length,
void MidiInterface::sendSysEx(int length,
const byte *const array,
bool ArrayContainsBoundaries)
{
@ -332,7 +329,7 @@ void MIDI_Class::sendSysEx(int length,
MIDI_SERIAL_PORT.write(array[i]);
}
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif
}
@ -343,7 +340,7 @@ void MIDI_Class::sendSysEx(int length,
When a MIDI unit receives this message,
it should tune its oscillators (if equipped with any).
*/
void MIDI_Class::sendTuneRequest()
void MidiInterface::sendTuneRequest()
{
sendRealTime(TuneRequest);
}
@ -355,7 +352,7 @@ void MIDI_Class::sendTuneRequest()
\param ValuesNibble MTC data
See MIDI Specification for more information.
*/
void MIDI_Class::sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble)
void MidiInterface::sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble)
{
const byte data = ( ((TypeNibble & 0x07) << 4) | (ValuesNibble & 0x0F) );
sendTimeCodeQuarterFrame(data);
@ -368,12 +365,12 @@ void MIDI_Class::sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble)
\param data if you want to encode directly the nibbles in your program,
you can send the byte here.
*/
void MIDI_Class::sendTimeCodeQuarterFrame(byte data)
void MidiInterface::sendTimeCodeQuarterFrame(byte data)
{
MIDI_SERIAL_PORT.write((byte)TimeCodeQuarterFrame);
MIDI_SERIAL_PORT.write(data);
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif
}
@ -382,25 +379,25 @@ void MIDI_Class::sendTimeCodeQuarterFrame(byte data)
/*! \brief Send a Song Position Pointer message.
\param Beats The number of beats since the start of the song.
*/
void MIDI_Class::sendSongPosition(unsigned int Beats)
void MidiInterface::sendSongPosition(unsigned int Beats)
{
MIDI_SERIAL_PORT.write((byte)SongPosition);
MIDI_SERIAL_PORT.write(Beats & 0x7F);
MIDI_SERIAL_PORT.write((Beats >> 7) & 0x7F);
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif
}
/*! \brief Send a Song Select message */
void MIDI_Class::sendSongSelect(byte SongNumber)
void MidiInterface::sendSongSelect(byte SongNumber)
{
MIDI_SERIAL_PORT.write((byte)SongSelect);
MIDI_SERIAL_PORT.write(SongNumber & 0x7F);
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
mRunningStatus_TX = InvalidType;
#endif
}
@ -411,9 +408,9 @@ void MIDI_Class::sendSongSelect(byte SongNumber)
\param Type The available Real Time types are:
Start, Stop, Continue, Clock, ActiveSensing and SystemReset.
You can also send a Tune Request with this method.
@see kMIDIType
@see MidiType
*/
void MIDI_Class::sendRealTime(kMIDIType Type)
void MidiInterface::sendRealTime(MidiType Type)
{
switch (Type)
{
@ -434,19 +431,19 @@ void MIDI_Class::sendRealTime(kMIDIType Type)
// Do not cancel Running Status for real-time messages as they can be
// interleaved within any message. Though, TuneRequest can be sent here,
// and as it is a System Common message, it must reset Running Status.
#if USE_RUNNING_STATUS
#if MIDI_USE_RUNNING_STATUS
if (Type == TuneRequest) mRunningStatus_TX = InvalidType;
#endif
}
#endif // COMPILE_MIDI_OUT
#endif // MIDI_BUILD_OUTPUT
// =============================================================================
// MIDI Input
// =============================================================================
#if COMPILE_MIDI_IN
#if MIDI_BUILD_INPUT
/*! \brief Read a MIDI message from the serial port
using the main input channel (see setInputChannel() for reference).
@ -456,7 +453,7 @@ void MIDI_Class::sendRealTime(kMIDIType Type)
If the Thru is enabled and the messages matches the filter,
it is sent back on the MIDI output.
*/
bool MIDI_Class::read()
bool MidiInterface::read()
{
return read(mInputChannel);
}
@ -465,7 +462,7 @@ bool MIDI_Class::read()
/*! \brief Reading/thru-ing method, the same as read()
with a given input channel to read on.
*/
bool MIDI_Class::read(const byte inChannel)
bool MidiInterface::read(const byte inChannel)
{
if (inChannel >= MIDI_CHANNEL_OFF)
return false; // MIDI Input disabled.
@ -475,7 +472,7 @@ bool MIDI_Class::read(const byte inChannel)
if (input_filter(inChannel))
{
#if (COMPILE_MIDI_OUT && COMPILE_MIDI_THRU)
#if (MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
thru_filter(inChannel);
#endif
@ -491,7 +488,7 @@ bool MIDI_Class::read(const byte inChannel)
// Private method: MIDI parser
bool MIDI_Class::parse(byte inChannel)
bool MidiInterface::parse(byte inChannel)
{
const byte bytes_available = MIDI_SERIAL_PORT.available();
@ -662,7 +659,7 @@ bool MIDI_Class::parse(byte inChannel)
// This is done by leaving the pending message as is,
// it will be completed on next calls.
mMessage.type = (kMIDIType)extracted;
mMessage.type = (MidiType)extracted;
mMessage.data1 = 0;
mMessage.data2 = 0;
mMessage.channel = 0;
@ -779,7 +776,7 @@ bool MIDI_Class::parse(byte inChannel)
// Private method: check if the received message is on the listened channel
bool MIDI_Class::input_filter(byte inChannel)
bool MidiInterface::input_filter(byte inChannel)
{
// This method handles recognition of channel
// (to know if the message is destinated to the Arduino)
@ -811,7 +808,7 @@ bool MIDI_Class::input_filter(byte inChannel)
// Private method: reset input attributes
void MIDI_Class::reset_input_attributes()
void MidiInterface::reset_input_attributes()
{
mPendingMessageIndex = 0;
mPendingMessageExpectedLenght = 0;
@ -819,102 +816,30 @@ void MIDI_Class::reset_input_attributes()
}
// Getters
/*! \brief Get the last received message's type
Returns an enumerated type. @see kMIDIType
*/
kMIDIType MIDI_Class::getType() const
{
return mMessage.type;
}
/*! \brief Get the channel of the message stored in the structure.
\return Channel range is 1 to 16.
For non-channel messages, this will return 0.
*/
byte MIDI_Class::getChannel() const
{
return mMessage.channel;
}
/*! \brief Get the first data byte of the last received message. */
byte MIDI_Class::getData1() const
{
return mMessage.data1;
}
/*! \brief Get the second data byte of the last received message. */
byte MIDI_Class::getData2() const
{
return mMessage.data2;
}
/*! \brief Get the System Exclusive byte array.
@see getSysExArrayLength to get the array's length in bytes.
*/
const byte * MIDI_Class::getSysExArray() const
{
return mMessage.sysex_array;
}
/*! \brief Get the lenght of the System Exclusive array.
It is coded using data1 as LSB and data2 as MSB.
\return The array's length, in bytes.
*/
unsigned int MIDI_Class::getSysExArrayLength() const
{
const unsigned int size = ((unsigned)(mMessage.data2) << 8) | mMessage.data1;
return (size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : size;
}
/*! \brief Check if a valid message is stored in the structure. */
bool MIDI_Class::check() const
{
return mMessage.valid;
}
// Setters
/*! \brief Set the value for the input MIDI channel
\param Channel 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 MIDI input.
*/
void MIDI_Class::setInputChannel(const byte Channel)
{
mInputChannel = Channel;
}
#if USE_CALLBACKS
void MIDI_Class::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; }
void MIDI_Class::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; }
void MIDI_Class::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; }
void MIDI_Class::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; }
void MIDI_Class::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
void MIDI_Class::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; }
void MIDI_Class::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
void MIDI_Class::setHandleSystemExclusive(void (*fptr)(byte * array, byte size)) { mSystemExclusiveCallback = fptr; }
void MIDI_Class::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
void MIDI_Class::setHandleSongPosition(void (*fptr)(unsigned int beats)) { mSongPositionCallback = fptr; }
void MIDI_Class::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
void MIDI_Class::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
void MIDI_Class::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
void MIDI_Class::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; }
void MIDI_Class::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; }
void MIDI_Class::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; }
void MIDI_Class::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; }
void MIDI_Class::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; }
void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; }
void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; }
void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; }
void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; }
void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; }
void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte * array, byte size)) { mSystemExclusiveCallback = fptr; }
void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned int beats)) { mSongPositionCallback = fptr; }
void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; }
void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; }
void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; }
void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; }
void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; }
/*! \brief Detach an external function from the given type.
@ -923,7 +848,7 @@ void MIDI_Class::setHandleSystemReset(void (*fptr)(void))
\param Type The type of message to unbind.
When a message of this type is received, no function will be called.
*/
void MIDI_Class::disconnectCallbackFromType(kMIDIType Type)
void MidiInterface::disconnectCallbackFromType(MidiType Type)
{
switch (Type)
{
@ -952,7 +877,7 @@ void MIDI_Class::disconnectCallbackFromType(kMIDIType Type)
// Private - launch callback function based on received type.
void MIDI_Class::launchCallback()
void MidiInterface::launchCallback()
{
// The order is mixed to allow frequent messages to trigger their callback faster.
switch (mMessage.type)
@ -994,49 +919,18 @@ void MIDI_Class::launchCallback()
#endif // USE_CALLBACKS
#endif // COMPILE_MIDI_IN
#endif // MIDI_BUILD_INPUT
// =============================================================================
// MIDI Soft Thru
// =============================================================================
#if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU)
/*! \brief Set the filter for thru mirroring
\param inThruFilterMode a filter mode
@see kThruFilterMode
*/
void MIDI_Class::setThruFilterMode(kThruFilterMode inThruFilterMode)
{
mThruFilterMode = inThruFilterMode;
if (mThruFilterMode != Off)
mThruActivated = true;
else
mThruActivated = false;
}
/*! \brief Setter method: turn message mirroring on. */
void MIDI_Class::turnThruOn(kThruFilterMode inThruFilterMode)
{
mThruActivated = true;
mThruFilterMode = inThruFilterMode;
}
/*! \brief Setter method: turn message mirroring off. */
void MIDI_Class::turnThruOff()
{
mThruActivated = false;
mThruFilterMode = Off;
}
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
// This method is called upon reception of a message
// and takes care of Thru filtering and sending.
void MIDI_Class::thru_filter(byte inChannel)
void MidiInterface::thru_filter(byte inChannel)
{
/*
@ -1142,3 +1036,5 @@ void MIDI_Class::thru_filter(byte inChannel)
}
#endif // Thru
END_MIDI_NAMESPACE

View File

@ -2,7 +2,7 @@
* @file MIDI.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino
* @version 3.2
* @version 4.0
* @author Francois Best
* @date 24/02/11
* license GPL Forty Seven Effects - 2011
@ -15,313 +15,101 @@
#include "midi_Settings.h"
#include "midi_Defs.h"
/*
###############################################################
# #
# CONFIGURATION AREA #
# #
# 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. #
# #
###############################################################
BEGIN_MIDI_NAMESPACE
/*! \brief The main class for MIDI handling.
*/
#define COMPILE_MIDI_IN 1 // Set this setting to 1 to use the MIDI input.
#define COMPILE_MIDI_OUT 1 // Set this setting to 1 to use the MIDI output.
#define COMPILE_MIDI_THRU 1 // Set this setting to 1 to use the MIDI Soft Thru feature
// Please note that the Thru will work only when both COMPILE_MIDI_IN and COMPILE_MIDI_OUT set to 1.
#define MIDI_SERIAL_PORT Serial // Change the number (to Serial1 for example) if you want
// to use a different serial port for MIDI I/O.
#define MIDI_USE_SOFTWARE_SERIAL 0 // Set to 1 to use SoftwareSerial instead of native serial ports.
#define MIDI_SOFTSERIAL_RX_PIN 1 // This pin number will be used for MIDI Input
#define MIDI_SOFTSERIAL_TX_PIN 2 // This pin number will be used for MIDI Output.
#define USE_RUNNING_STATUS 1 // 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 USE_CALLBACKS 1 // Set this to 1 if you want to use callback handlers (to bind your functions to the library).
// To use the callbacks, you need to have COMPILE_MIDI_IN set to 1
#define USE_1BYTE_PARSING 1 // Each call to MIDI.read will only parse one byte (might be faster).
// END OF CONFIGURATION AREA
// (do not modify anything under this line unless you know what you are doing)
#define MIDI_BAUDRATE 31250
#define MIDI_CHANNEL_OMNI 0
#define MIDI_CHANNEL_OFF 17 // and over
#define MIDI_SYSEX_ARRAY_SIZE 255 // Maximum size is 65535 bytes.
#define MIDI_PITCHBEND_MIN -8192
#define MIDI_PITCHBEND_MAX 8191
/*! Type definition for practical use
(because "unsigned char" is a bit long to write.. )
*/
typedef uint8_t byte;
typedef uint16_t word;
/*! Enumeration of MIDI types */
enum kMIDIType
{
NoteOff = 0x80, ///< Note Off
NoteOn = 0x90, ///< Note On
AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch
ControlChange = 0xB0, ///< Control Change / Channel Mode
ProgramChange = 0xC0, ///< Program Change
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
PitchBend = 0xE0, ///< Pitch Bend
SystemExclusive = 0xF0, ///< System Exclusive
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
SongPosition = 0xF2, ///< System Common - Song Position Pointer
SongSelect = 0xF3, ///< System Common - Song Select
TuneRequest = 0xF6, ///< System Common - Tune Request
Clock = 0xF8, ///< System Real Time - Timing Clock
Start = 0xFA, ///< System Real Time - Start
Continue = 0xFB, ///< System Real Time - Continue
Stop = 0xFC, ///< System Real Time - Stop
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
SystemReset = 0xFF, ///< System Real Time - System Reset
InvalidType = 0x00 ///< For notifying errors
};
/*! Enumeration of Thru filter modes */
enum kThruFilterMode {
Off = 0, ///< Thru disabled (nothing passes through).
Full = 1, ///< Fully enabled Thru (every incoming message is sent back).
SameChannel = 2, ///< Only the messages on the Input Channel will be sent back.
DifferentChannel = 3 ///< All the messages but the ones on the Input Channel will be sent back.
};
enum eMIDICCNumber
{
// High resolution Continuous Controllers MSB (+32 for LSB) ----------------
BankSelect = 0,
ModulationWheel = 1,
BreathController = 2,
// CC3 undefined
FootController = 4,
PortamentoTime = 5,
DataEntry = 6,
ChannelVolume = 7,
Balance = 8,
// CC9 undefined
Pan = 10,
ExpressionController = 11,
EffectControl1 = 12,
EffectControl2 = 13,
// CC14 undefined
// CC15 undefined
GeneralPurposeController1 = 16,
GeneralPurposeController2 = 17,
GeneralPurposeController3 = 18,
GeneralPurposeController4 = 19,
// Switches ----------------------------------------------------------------
Sustain = 64,
Portamento = 65,
Sostenuto = 66,
SoftPedal = 67,
Legato = 68,
Hold2 = 69,
// Low resolution continuous controllers -----------------------------------
SoundController1 = 70, ///< Synth: Sound Variation FX: Exciter On/Off
SoundController2 = 71, ///< Synth: Harmonic Content FX: Compressor On/Off
SoundController3 = 72, ///< Synth: Release Time FX: Distortion On/Off
SoundController4 = 73, ///< Synth: Attack Time FX: EQ On/Off
SoundController5 = 74, ///< Synth: Brightness FX: Expander On/Off
SoundController6 = 75, ///< Synth: Decay Time FX: Reverb On/Off
SoundController7 = 76, ///< Synth: Vibrato Rate FX: Delay On/Off
SoundController8 = 77, ///< Synth: Vibrato Depth FX: Pitch Transpose On/Off
SoundController9 = 78, ///< Synth: Vibrato Delay FX: Flange/Chorus On/Off
SoundController10 = 79, ///< Synth: Undefined FX: Special Effects On/Off
GeneralPurposeController5 = 80,
GeneralPurposeController6 = 81,
GeneralPurposeController7 = 82,
GeneralPurposeController8 = 83,
PortamentoControl = 84,
// CC85 to CC90 undefined
Effects1 = 91, ///< Reverb send level
Effects2 = 92, ///< Tremolo depth
Effects3 = 93, ///< Chorus send level
Effects4 = 94, ///< Celeste depth
Effects5 = 95, ///< Phaser depth
// Channel Mode messages ---------------------------------------------------
AllSoundOff = 120,
ResetAllControllers = 121,
LocalControl = 122,
AllNotesOff = 123,
OmniModeOff = 124,
OmniModeOn = 125,
MonoModeOn = 126,
PolyModeOn = 127
};
/*! The midimsg structure contains decoded data
of a MIDI message read from the serial port
with read() or thru().
*/
struct midimsg
{
/*! The MIDI channel on which the message was recieved.
\n Value goes from 1 to 16.
*/
byte channel;
/*! The type of the message
(see the define section for types reference)
*/
kMIDIType type;
/*! The first data byte.
\n Value goes from 0 to 127.
*/
byte data1;
/*! The second data byte.
If the message is only 2 bytes long, this one is null.
\n Value goes from 0 to 127.
*/
byte data2;
/*! System Exclusive dedicated byte array.
\n Array length is stocked on 16 bits,
in data1 (LSB) and data2 (MSB)
*/
byte sysex_array[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 The main class for MIDI handling.\n
See member descriptions to know how to use it,
or check out the examples supplied with the library.
*/
class MIDI_Class
//template<typename Uart>
class MidiInterface
{
public:
MidiInterface();
~MidiInterface();
public:
// =========================================================================
// Constructor and Destructor
MIDI_Class();
~MIDI_Class();
void begin(const byte inChannel = 1);
void begin(byte inChannel = 1);
// =========================================================================
// -------------------------------------------------------------------------
// MIDI Output
#if COMPILE_MIDI_OUT // Start compilation block
#if MIDI_BUILD_OUTPUT
public:
void sendNoteOn(byte inNoteNumber,
byte inVelocity,
Channel inChannel);
void sendNoteOn(byte NoteNumber,byte Velocity,byte Channel);
void sendNoteOff(byte NoteNumber,byte Velocity,byte Channel);
void sendProgramChange(byte ProgramNumber,byte Channel);
void sendControlChange(byte ControlNumber, byte ControlValue,byte Channel);
void sendPitchBend(int PitchValue,byte Channel);
void sendPitchBend(double PitchValue,byte Channel);
void sendPolyPressure(byte NoteNumber,byte Pressure,byte Channel);
void sendAfterTouch(byte Pressure,byte Channel);
void sendSysEx(int length, const byte *const array,bool ArrayContainsBoundaries = false);
void sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble);
void sendTimeCodeQuarterFrame(byte data);
void sendSongPosition(unsigned int Beats);
void sendSongSelect(byte SongNumber);
void sendNoteOff(byte inNoteNumber,
byte inVelocity,
Channel inChannel);
void sendProgramChange(byte inProgramNumber,
Channel inChannel);
void sendControlChange(byte inControlNumber,
byte inControlValue,
Channel inChannel);
void sendPitchBend(int inPitchValue, Channel inChannel);
void sendPitchBend(double inPitchValue, Channel inChannel);
void sendPolyPressure(byte inNoteNumber,
byte inPressure,
Channel inChannel);
void sendAfterTouch(byte inPressure,
Channel inChannel);
void sendSysEx(unsigned int inLength,
const byte* inArray,
bool inArrayContainsBoundaries = false);
void sendTimeCodeQuarterFrame(byte inTypeNibble,
byte inValuesNibble);
void sendTimeCodeQuarterFrame(byte inData);
void sendSongPosition(unsigned int inBeats);
void sendSongSelect(byte inSongNumber);
void sendTuneRequest();
void sendRealTime(kMIDIType Type);
void sendRealTime(MidiType inType);
void send(kMIDIType type, byte param1, byte param2, byte channel);
void send(MidiType inType,
DataByte inData1,
DataByte inData2,
Channel inChannel);
private:
inline StatusByte getStatus(MidiType inType,
Channel inChannel) const;
const byte genstatus(const kMIDIType inType,const byte inChannel) const;
#endif // MIDI_BUILD_OUTPUT
// Attributes
#if USE_RUNNING_STATUS
byte mRunningStatus_TX;
#endif // USE_RUNNING_STATUS
#endif // COMPILE_MIDI_OUT
// =========================================================================
// -------------------------------------------------------------------------
// MIDI Input
#if COMPILE_MIDI_IN // Start compilation block
#if MIDI_BUILD_INPUT
public:
bool read();
bool read(const byte Channel);
bool read(Channel inChannel);
// Getters
kMIDIType getType() const;
byte getChannel() const;
byte getData1() const;
byte getData2() const;
const byte * getSysExArray() const;
unsigned int getSysExArrayLength() const;
bool check() const;
public:
inline MidiType getType() const;
inline Channel getChannel() const;
inline DataByte getData1() const;
inline DataByte getData2() const;
inline const byte* getSysExArray() const;
inline unsigned int getSysExArrayLength() const;
inline bool check() const;
byte getInputChannel() const
{
return mInputChannel;
}
// Setters
void setInputChannel(const byte Channel);
/*! \brief Extract an enumerated MIDI type from a status byte.
This is a utility static method, used internally, made public so you can handle kMIDITypes more easily.
*/
static inline const kMIDIType getTypeFromStatusByte(const byte inStatus)
{
if ((inStatus < 0x80) ||
(inStatus == 0xF4) ||
(inStatus == 0xF5) ||
(inStatus == 0xF9) ||
(inStatus == 0xFD)) return InvalidType; // data bytes and undefined.
if (inStatus < 0xF0) return (kMIDIType)(inStatus & 0xF0); // Channel message, remove channel nibble.
else return (kMIDIType)inStatus;
}
public:
inline Channel getInputChannel() const;
inline void setInputChannel(Channel inChannel);
public:
static inline MidiType getTypeFromStatusByte(const byte inStatus);
private:
@ -366,7 +154,7 @@ public:
void setHandleActiveSensing(void (*fptr)(void));
void setHandleSystemReset(void (*fptr)(void));
void disconnectCallbackFromType(kMIDIType Type);
void disconnectCallbackFromType(MidiType Type);
private:
@ -393,39 +181,46 @@ private:
#endif // USE_CALLBACKS
#endif // COMPILE_MIDI_IN
#endif // MIDI_BUILD_INPUT
// =========================================================================
// MIDI Soft Thru
#if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU)
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
public:
inline MidiFilterMode getFilterMode() const;
inline bool getThruState() const;
// Getters
kThruFilterMode getFilterMode() const { return mThruFilterMode; }
bool getThruState() const { return mThruActivated; }
// Setters
void turnThruOn(kThruFilterMode inThruFilterMode = Full);
void turnThruOff();
void setThruFilterMode(const kThruFilterMode inThruFilterMode);
inline void turnThruOn(MidiFilterMode inThruFilterMode = Full);
inline void turnThruOff();
inline void setThruFilterMode(MidiFilterMode inThruFilterMode);
private:
void thru_filter(byte inChannel);
bool mThruActivated;
kThruFilterMode mThruFilterMode;
bool mThruActivated : 1;
MidiFilterMode mThruFilterMode : 7;
#endif // Thru
// Attributes
#if MIDI_USE_RUNNING_STATUS
StatusByte mRunningStatus_TX;
#endif // MIDI_USE_RUNNING_STATUS
};
extern MIDI_Class MIDI;
END_MIDI_NAMESPACE
#endif // LIB_MIDI_H_
#if MIDI_AUTO_INSTANCIATE
extern midi::MidiInterface MIDI;
#endif
#include "midi_Inline.hpp"

View File

@ -2,7 +2,7 @@
* @file midi_Defs.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Definitions
* @version 3.5
* @version 4.0
* @author Francois Best
* @date 24/02/11
* license GPL Forty Seven Effects - 2011
@ -15,23 +15,31 @@
BEGIN_MIDI_NAMESPACE
// -----------------------------------------------------------------------------
#define MIDI_CHANNEL_OMNI 0
#define MIDI_CHANNEL_OFF 17 // and over
#define MIDI_CHANNEL_OFF 17 // and over
#define MIDI_PITCHBEND_MIN -8192
#define MIDI_PITCHBEND_MAX 8191
// -----------------------------------------------------------------------------
// Type definitions
/*! Type definition for practical use
(because "unsigned char" is a bit long to write.. )
*/
typedef uint8_t byte;
typedef uint16_t word;
typedef byte StatusByte;
typedef byte DataByte;
typedef byte Channel;
typedef byte FilterMode;
// -----------------------------------------------------------------------------
/*! Enumeration of MIDI types */
enum kMIDIType
enum MidiType
{
InvalidType = 0x00, ///< For notifying errors
NoteOff = 0x80, ///< Note Off
NoteOn = 0x90, ///< Note On
AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch
@ -50,19 +58,22 @@ enum kMIDIType
Stop = 0xFC, ///< System Real Time - Stop
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
SystemReset = 0xFF, ///< System Real Time - System Reset
InvalidType = 0x00 ///< For notifying errors
};
// -----------------------------------------------------------------------------
/*! Enumeration of Thru filter modes */
enum kThruFilterMode {
enum MidiFilterMode
{
Off = 0, ///< Thru disabled (nothing passes through).
Full = 1, ///< Fully enabled Thru (every incoming message is sent back).
SameChannel = 2, ///< Only the messages on the Input Channel will be sent back.
DifferentChannel = 3 ///< All the messages but the ones on the Input Channel will be sent back.
DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back.
};
// -----------------------------------------------------------------------------
enum eMIDICCNumber
enum MidiControlChangeNumber
{
// High resolution Continuous Controllers MSB (+32 for LSB) ----------------
BankSelect = 0,
@ -92,7 +103,7 @@ enum eMIDICCNumber
Sostenuto = 66,
SoftPedal = 67,
Legato = 68,
Hold2 = 69,
Hold = 69,
// Low resolution continuous controllers -----------------------------------
SoundController1 = 70, ///< Synth: Sound Variation FX: Exciter On/Off
@ -129,40 +140,41 @@ enum eMIDICCNumber
};
// -----------------------------------------------------------------------------
/*! The midimsg structure contains decoded data
of a MIDI message read from the serial port
with read() or thru().
*/
struct midimsg
struct Message
{
/*! The MIDI channel on which the message was recieved.
\n Value goes from 1 to 16.
*/
byte channel;
Channel channel;
/*! The type of the message
(see the define section for types reference)
(see the MidiType enum for types reference)
*/
kMIDIType type;
MidiType type;
/*! The first data byte.
\n Value goes from 0 to 127.
*/
byte data1;
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.
*/
byte data2;
DataByte data2;
/*! System Exclusive dedicated byte array.
\n Array length is stocked on 16 bits,
in data1 (LSB) and data2 (MSB)
*/
byte sysex_array[MIDI_SYSEX_ARRAY_SIZE];
DataByte sysex_array[MIDI_SYSEX_ARRAY_SIZE];
/*! This boolean indicates if the message is valid or not.
There is no channel consideration here,
@ -172,5 +184,4 @@ struct midimsg
};
END_MIDI_NAMESPACE

167
src/midi_Inline.hpp Normal file
View File

@ -0,0 +1,167 @@
/*!
* @file midi_Inline.hpp
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Inline implementations
* @version 4.0
* @author Francois Best
* @date 24/02/11
* license GPL Forty Seven Effects - 2011
*/
#pragma once
BEGIN_MIDI_NAMESPACE
#if MIDI_BUILD_OUTPUT
StatusByte MidiInterface::getStatus(kMIDIType inType,
Channel inChannel) const
{
return ((byte)inType | ((inChannel - 1) & 0x0F));
}
#endif // MIDI_BUILD_OUTPUT
// -----------------------------------------------------------------------------
#if MIDI_BUILD_INPUT
/*! \brief Get the last received message's type
Returns an enumerated type. @see MidiType
*/
MidiType MidiInterface::getType() const
{
return mMessage.type;
}
/*! \brief Get the channel of the message stored in the structure.
\return Channel range is 1 to 16.
For non-channel messages, this will return 0.
*/
Channel MidiInterface::getChannel() const
{
return mMessage.channel;
}
/*! \brief Get the first data byte of the last received message. */
DataByte MidiInterface::getData1() const
{
return mMessage.data1;
}
/*! \brief Get the second data byte of the last received message. */
DataByte MidiInterface::getData2() const
{
return mMessage.data2;
}
/*! \brief Get the System Exclusive byte array.
@see getSysExArrayLength to get the array's length in bytes.
*/
const byte* MidiInterface::getSysExArray() const
{
return mMessage.sysex_array;
}
/*! \brief Get the lenght of the System Exclusive array.
It is coded using data1 as LSB and data2 as MSB.
\return The array's length, in bytes.
*/
unsigned int MidiInterface::getSysExArrayLength() const
{
const unsigned int size = ((unsigned)(mMessage.data2) << 8) | mMessage.data1;
return (size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : size;
}
/*! \brief Check if a valid message is stored in the structure. */
bool MidiInterface::check() const
{
return mMessage.valid;
}
// -----------------------------------------------------------------------------
Channel MidiInterface::getInputChannel() const
{
return mInputChannel;
}
/*! \brief Set the value for the input MIDI channel
\param Channel 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.
*/
void MidiInterface::setInputChannel(Channel inChannel)
{
mInputChannel = inChannel;
}
// -----------------------------------------------------------------------------
/*! \brief Extract an enumerated MIDI type from a status byte.
This is a utility static method, used internally,
made public so you can handle MidiTypes more easily.
*/
MidiType MidiInterface::getTypeFromStatusByte(const byte inStatus)
{
if ((inStatus < 0x80) ||
(inStatus == 0xF4) ||
(inStatus == 0xF5) ||
(inStatus == 0xF9) ||
(inStatus == 0xFD)) return InvalidType; // data bytes and undefined.
if (inStatus < 0xF0) return (MidiType)(inStatus & 0xF0); // Channel message, remove channel nibble.
else return (MidiType)inStatus;
}
#endif // MIDI_BUILD_INPUT
// -----------------------------------------------------------------------------
#if (MIDI_BUILD_INPUT && MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU)
MidiFilterMode MidiInterface::getFilterMode() const
{
return mThruFilterMode;
}
bool MidiInterface::getThruState() const
{
return mThruActivated;
}
/*! \brief Setter method: turn message mirroring on. */
void MidiInterface::turnThruOn(MidiFilterMode inThruFilterMode)
{
mThruActivated = true;
mThruFilterMode = inThruFilterMode;
}
/*! \brief Setter method: turn message mirroring off. */
void MidiInterface::turnThruOff()
{
mThruActivated = false;
mThruFilterMode = Off;
}
/*! \brief Set the filter for thru mirroring
\param inThruFilterMode a filter mode
@see MidiFilterMode
*/
void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMode)
{
mThruFilterMode = inThruFilterMode;
if (mThruFilterMode != Off)
mThruActivated = true;
else
mThruActivated = false;
}
#endif // MIDI_BUILD_THRU
END_MIDI_NAMESPACE

View File

@ -2,7 +2,7 @@
* @file midi_Namespace.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Namespace declaration
* @version 3.5
* @version 4.0
* @author Francois Best
* @date 24/02/11
* license GPL Forty Seven Effects - 2011

View File

@ -27,23 +27,25 @@ BEGIN_MIDI_NAMESPACE
// (MIDI in, out, thru), or to 0 to disable the feature and save space.
// Note that the Thru can only work if in and out are enabled.
#define MIDI_BUILD_INPUT 1
#define MIDI_BUILD_OUTPUT 1
#define MIDI_BUILD_THRU 1
#define MIDI_BUILD_INPUT 1
#define MIDI_BUILD_OUTPUT 1
#define MIDI_BUILD_THRU 1
// Create a MIDI object automatically on the port defined with MIDI_SERIAL_PORT.
#define MIDI_AUTO_INSTANCIATE 1
// -----------------------------------------------------------------------------
// Serial port configuration
// Change the number (to Serial1 for example)
// if you want to use a different serial port for MIDI I/O.
#define MIDI_SERIAL_PORT Serial
// Set the default port to use for MIDI.
#define MIDI_SERIAL_PORT Serial
// Software serial options
#define MIDI_USE_SOFTWARE_SERIAL 0
#define MIDI_USE_SOFTWARE_SERIAL 0
#if MIDI_USE_SOFTWARE_SERIAL
#define MIDI_SOFTSERIAL_RX_PIN 1 // Pin number to use for MIDI Input
#define MIDI_SOFTSERIAL_TX_PIN 2 // Pin number to use for MIDI Output.
#define MIDI_SOFTSERIAL_RX_PIN 1 // Pin number to use for MIDI Input
#define MIDI_SOFTSERIAL_TX_PIN 2 // Pin number to use for MIDI Output
#endif
// -----------------------------------------------------------------------------
@ -52,11 +54,10 @@ BEGIN_MIDI_NAMESPACE
// 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
#define MIDI_USE_1BYTE_PARSING 1
#define MIDI_USE_RUNNING_STATUS 1
#define MIDI_USE_1BYTE_PARSING 1
#define MIDI_BAUDRATE 31250
#define MIDI_SYSEX_ARRAY_SIZE 255 // Maximum size is 65535 bytes.
#define MIDI_BAUDRATE 31250
#define MIDI_SYSEX_ARRAY_SIZE 255 // Maximum size is 65535 bytes.
END_MIDI_NAMESPACE