By standard midi library I mean the following midi.h file that comes with arduino:
#ifndef LIB_MIDI_H_
#define LIB_MIDI_H_
#include <inttypes.h>
#define COMPILE_MIDI_IN 1 // Set this setting to 1 to use the MIDI input.
#define COMPILE_MIDI_OUT 0 // Set this setting to 1 to use the MIDI output.
#define COMPILE_MIDI_THRU 0 // 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 USE_SERIAL_PORT Serial // Change the number (to Serial1 for example) if you want
// to use a different serial port for MIDI I/O.
#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 with controlling you 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
// 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
/*! 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.
};
/*! The midimsg structure contains decoded data of a MIDI message read from the serial port with read() or thru(). \n */
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.\n If the message is SysEx, this byte contains the array length. */
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 in data1. */
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 {
public:
// Constructor and Destructor
MIDI_Class();
~MIDI_Class();
void begin(const byte inChannel = 1);
/* ####### INPUT COMPILATION BLOCK ####### */
#if COMPILE_MIDI_IN
public:
bool read();
bool read(const byte Channel);
// Getters
kMIDIType getType();
byte getChannel();
byte getData1();
byte getData2();
byte * getSysExArray();
bool check();
byte getInputChannel() { 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;
}
#if USE_CALLBACKS
void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity));
void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity));
void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure));
void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value));
void setHandleProgramChange(void (*fptr)(byte channel, byte number));
void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
void setHandlePitchBend(void (*fptr)(byte channel, int bend));
void setHandleSystemExclusive(void (*fptr)(byte * array, byte size));
void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
void setHandleSongPosition(void (*fptr)(unsigned int beats));
void setHandleSongSelect(void (*fptr)(byte songnumber));
void setHandleTuneRequest(void (*fptr)(void));
void setHandleClock(void (*fptr)(void));
void setHandleStart(void (*fptr)(void));
void setHandleContinue(void (*fptr)(void));
void setHandleStop(void (*fptr)(void));
void setHandleActiveSensing(void (*fptr)(void));
void setHandleSystemReset(void (*fptr)(void));
void disconnectCallbackFromType(kMIDIType Type);
#endif // USE_CALLBACKS
private:
bool input_filter(byte inChannel);
bool parse(byte inChannel);
void reset_input_attributes();
// Attributes
byte mRunningStatus_RX;
byte mInputChannel;
byte mPendingMessage[MIDI_SYSEX_ARRAY_SIZE];
byte mPendingMessageExpectedLenght;
byte mPendingMessageIndex;
midimsg mMessage;
#if USE_CALLBACKS
void launchCallback();
void (*mNoteOffCallback)(byte channel, byte note, byte velocity);
void (*mNoteOnCallback)(byte channel, byte note, byte velocity);
void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity);
void (*mControlChangeCallback)(byte channel, byte, byte);
void (*mProgramChangeCallback)(byte channel, byte);
void (*mAfterTouchChannelCallback)(byte channel, byte);
void (*mPitchBendCallback)(byte channel, int);
void (*mSystemExclusiveCallback)(byte * array, byte size);
void (*mTimeCodeQuarterFrameCallback)(byte data);
void (*mSongPositionCallback)(unsigned int beats);
void (*mSongSelectCallback)(byte songnumber);
void (*mTuneRequestCallback)(void);
void (*mClockCallback)(void);
void (*mStartCallback)(void);
void (*mContinueCallback)(void);
void (*mStopCallback)(void);
void (*mActiveSensingCallback)(void);
void (*mSystemResetCallback)(void);
#endif // USE_CALLBACKS
#endif // COMPILE_MIDI_IN
extern MIDI_Class MIDI;
#endif // LIB_MIDI_H_
(I've had to remove some irrelevant parts of this code to fit it in this post)
As for my code, I'm using a similar method to the one of this page:
http://adrianfreed.com/content/arduino-sketch-high-frequency-precision-sine-wave-tone-sound-synthesis