-
Notifications
You must be signed in to change notification settings - Fork 2
/
MIDI.h
316 lines (230 loc) · 10.7 KB
/
MIDI.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*!
* @file MIDI.h
* Project MIDI Library
* @brief MIDI Library for the Arduino
* Version 3.2
* @author Francois Best
* @date 24/02/11
* License GPL Forty Seven Effects - 2011
*/
#ifndef LIB_MIDI_H_
#define LIB_MIDI_H_
#include <inttypes.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. #
# #
###############################################################
*/
#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
#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.
/*! 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 */
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 {
public:
// Constructor and Destructor
MIDI_Class();
~MIDI_Class();
void begin(const byte inChannel = 1);
/* ####### OUTPUT COMPILATION BLOCK ####### */
#if COMPILE_MIDI_OUT
public:
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(unsigned 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 sendTuneRequest();
void sendRealTime(kMIDIType Type);
void send(kMIDIType type, byte param1, byte param2, byte channel);
private:
const byte genstatus(const kMIDIType inType,const byte inChannel) const;
// Attributes
#if USE_RUNNING_STATUS
byte mRunningStatus_TX;
#endif // USE_RUNNING_STATUS
#endif // COMPILE_MIDI_OUT
/* ####### INPUT COMPILATION BLOCK ####### */
#if COMPILE_MIDI_IN
public:
bool read();
bool read(const byte Channel);
// Getters
kMIDIType getType() const;
byte getChannel() const;
byte getData1() const;
byte getData2() const;
const byte * getSysExArray() const;
unsigned int getSysExArrayLength() const;
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;
}
#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];
unsigned int mPendingMessageExpectedLenght;
unsigned int mPendingMessageIndex; // Extended to unsigned int for larger sysex payloads.
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
/* ####### THRU COMPILATION BLOCK ####### */
#if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
public:
// Getters
kThruFilterMode getFilterMode() const { return mThruFilterMode; }
bool getThruState() const { return mThruActivated; }
// Setters
void turnThruOn(kThruFilterMode inThruFilterMode = Full);
void turnThruOff();
void setThruFilterMode(const kThruFilterMode inThruFilterMode);
private:
void thru_filter(byte inChannel);
bool mThruActivated;
kThruFilterMode mThruFilterMode;
#endif // Thru
};
extern MIDI_Class MIDI;
#endif // LIB_MIDI_H_