Ported from Arduino MIDI library Orignal: http://www.arduino.cc/playground/Main/MIDILibrary use Serial (UART)

Dependents:   MIDI_sample MIDI_usb_bridge MIDI_Interpreter midi-timer ... more

Committer:
okini3939
Date:
Tue Jan 08 03:32:22 2013 +0000
Revision:
1:0eeca7deec08
Parent:
0:713ef38fead1
disable loopback

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:713ef38fead1 1 /*!
okini3939 0:713ef38fead1 2 * @file MIDI.cpp
okini3939 0:713ef38fead1 3 * Project MIDI Library
okini3939 0:713ef38fead1 4 * @brief MIDI Library for the Arduino
okini3939 0:713ef38fead1 5 * @version 3.2
okini3939 0:713ef38fead1 6 * @author Francois Best
okini3939 0:713ef38fead1 7 * @date 24/02/11
okini3939 0:713ef38fead1 8 * license GPL Forty Seven Effects - 2011
okini3939 0:713ef38fead1 9 */
okini3939 0:713ef38fead1 10 /*
okini3939 0:713ef38fead1 11 * Ported for mbed by Hiroshi Suga
okini3939 0:713ef38fead1 12 * Orignal: http://www.arduino.cc/playground/Main/MIDILibrary
okini3939 0:713ef38fead1 13 */
okini3939 0:713ef38fead1 14
okini3939 0:713ef38fead1 15 #include "MIDI.h"
okini3939 0:713ef38fead1 16 #include "mbed.h"
okini3939 0:713ef38fead1 17
okini3939 0:713ef38fead1 18
okini3939 0:713ef38fead1 19
okini3939 0:713ef38fead1 20 /*! \brief Default constructor for MIDI. */
okini3939 0:713ef38fead1 21 MIDI::MIDI(PinName p_tx, PinName p_rx) : _midi(p_tx, p_rx)
okini3939 0:713ef38fead1 22 {
okini3939 0:713ef38fead1 23
okini3939 0:713ef38fead1 24 #if USE_CALLBACKS
okini3939 0:713ef38fead1 25
okini3939 0:713ef38fead1 26 // Initialise callbacks to NULL pointer
okini3939 0:713ef38fead1 27 mNoteOffCallback = NULL;
okini3939 0:713ef38fead1 28 mNoteOnCallback = NULL;
okini3939 0:713ef38fead1 29 mAfterTouchPolyCallback = NULL;
okini3939 0:713ef38fead1 30 mControlChangeCallback = NULL;
okini3939 0:713ef38fead1 31 mProgramChangeCallback = NULL;
okini3939 0:713ef38fead1 32 mAfterTouchChannelCallback = NULL;
okini3939 0:713ef38fead1 33 mPitchBendCallback = NULL;
okini3939 0:713ef38fead1 34 mSystemExclusiveCallback = NULL;
okini3939 0:713ef38fead1 35 mTimeCodeQuarterFrameCallback = NULL;
okini3939 0:713ef38fead1 36 mSongPositionCallback = NULL;
okini3939 0:713ef38fead1 37 mSongSelectCallback = NULL;
okini3939 0:713ef38fead1 38 mTuneRequestCallback = NULL;
okini3939 0:713ef38fead1 39 mClockCallback = NULL;
okini3939 0:713ef38fead1 40 mStartCallback = NULL;
okini3939 0:713ef38fead1 41 mContinueCallback = NULL;
okini3939 0:713ef38fead1 42 mStopCallback = NULL;
okini3939 0:713ef38fead1 43 mActiveSensingCallback = NULL;
okini3939 0:713ef38fead1 44 mSystemResetCallback = NULL;
okini3939 0:713ef38fead1 45
okini3939 0:713ef38fead1 46 #endif
okini3939 0:713ef38fead1 47
okini3939 0:713ef38fead1 48 }
okini3939 0:713ef38fead1 49
okini3939 0:713ef38fead1 50
okini3939 0:713ef38fead1 51 /*! \brief Default destructor for MIDI.
okini3939 0:713ef38fead1 52
okini3939 0:713ef38fead1 53 This is not really useful for the Arduino, as it is never called...
okini3939 0:713ef38fead1 54 */
okini3939 0:713ef38fead1 55 MIDI::~MIDI()
okini3939 0:713ef38fead1 56 {
okini3939 0:713ef38fead1 57
okini3939 0:713ef38fead1 58 }
okini3939 0:713ef38fead1 59
okini3939 0:713ef38fead1 60
okini3939 0:713ef38fead1 61 /*! \brief Call the begin method in the setup() function of the Arduino.
okini3939 0:713ef38fead1 62
okini3939 0:713ef38fead1 63 All parameters are set to their default values:
okini3939 0:713ef38fead1 64 - Input channel set to 1 if no value is specified
okini3939 0:713ef38fead1 65 - Full thru mirroring
okini3939 0:713ef38fead1 66 */
okini3939 0:713ef38fead1 67 void MIDI::begin(const byte inChannel)
okini3939 0:713ef38fead1 68 {
okini3939 0:713ef38fead1 69
okini3939 0:713ef38fead1 70 // Initialise the Serial port
okini3939 0:713ef38fead1 71 USE_SERIAL_PORT.baud(MIDI_BAUDRATE);
okini3939 0:713ef38fead1 72
okini3939 0:713ef38fead1 73
okini3939 0:713ef38fead1 74 #if COMPILE_MIDI_OUT
okini3939 0:713ef38fead1 75
okini3939 0:713ef38fead1 76 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 77
okini3939 0:713ef38fead1 78 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 79
okini3939 0:713ef38fead1 80 #endif // USE_RUNNING_STATUS
okini3939 0:713ef38fead1 81
okini3939 0:713ef38fead1 82 #endif // COMPILE_MIDI_OUT
okini3939 0:713ef38fead1 83
okini3939 0:713ef38fead1 84
okini3939 0:713ef38fead1 85 #if COMPILE_MIDI_IN
okini3939 0:713ef38fead1 86
okini3939 0:713ef38fead1 87 mInputChannel = inChannel;
okini3939 0:713ef38fead1 88 mRunningStatus_RX = InvalidType;
okini3939 0:713ef38fead1 89 mPendingMessageIndex = 0;
okini3939 0:713ef38fead1 90 mPendingMessageExpectedLenght = 0;
okini3939 0:713ef38fead1 91
okini3939 0:713ef38fead1 92 mMessage.valid = false;
okini3939 0:713ef38fead1 93 mMessage.type = InvalidType;
okini3939 0:713ef38fead1 94 mMessage.channel = 0;
okini3939 0:713ef38fead1 95 mMessage.data1 = 0;
okini3939 0:713ef38fead1 96 mMessage.data2 = 0;
okini3939 0:713ef38fead1 97
okini3939 0:713ef38fead1 98 #endif // COMPILE_MIDI_IN
okini3939 0:713ef38fead1 99
okini3939 0:713ef38fead1 100
okini3939 0:713ef38fead1 101 #if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
okini3939 0:713ef38fead1 102
okini3939 0:713ef38fead1 103 mThruFilterMode = Full;
okini3939 0:713ef38fead1 104 mThruActivated = true;
okini3939 0:713ef38fead1 105
okini3939 0:713ef38fead1 106 #endif // Thru
okini3939 0:713ef38fead1 107
okini3939 0:713ef38fead1 108 }
okini3939 0:713ef38fead1 109
okini3939 0:713ef38fead1 110
okini3939 0:713ef38fead1 111 #if COMPILE_MIDI_OUT
okini3939 0:713ef38fead1 112
okini3939 0:713ef38fead1 113 // Private method for generating a status byte from channel and type
okini3939 0:713ef38fead1 114 byte MIDI::genstatus(const kMIDIType inType,
okini3939 0:713ef38fead1 115 const byte inChannel) const
okini3939 0:713ef38fead1 116 {
okini3939 0:713ef38fead1 117
okini3939 0:713ef38fead1 118 return ((byte)inType | ((inChannel-1) & 0x0F));
okini3939 0:713ef38fead1 119
okini3939 0:713ef38fead1 120 }
okini3939 0:713ef38fead1 121
okini3939 0:713ef38fead1 122
okini3939 0:713ef38fead1 123 /*! \brief Generate and send a MIDI message from the values given.
okini3939 0:713ef38fead1 124 \param type The message type (see type defines for reference)
okini3939 0:713ef38fead1 125 \param data1 The first data byte.
okini3939 0:713ef38fead1 126 \param data2 The second data byte (if the message contains only 1 data byte, set this one to 0).
okini3939 0:713ef38fead1 127 \param channel The output channel on which the message will be sent (values from 1 to 16). Note: you cannot send to OMNI.
okini3939 0:713ef38fead1 128
okini3939 0:713ef38fead1 129 This is an internal method, use it only if you need to send raw data from your code, at your own risks.
okini3939 0:713ef38fead1 130 */
okini3939 0:713ef38fead1 131 void MIDI::send(kMIDIType type,
okini3939 0:713ef38fead1 132 byte data1,
okini3939 0:713ef38fead1 133 byte data2,
okini3939 0:713ef38fead1 134 byte channel)
okini3939 0:713ef38fead1 135 {
okini3939 0:713ef38fead1 136
okini3939 0:713ef38fead1 137 // Then test if channel is valid
okini3939 0:713ef38fead1 138 if (channel >= MIDI_CHANNEL_OFF || channel == MIDI_CHANNEL_OMNI || type < NoteOff) {
okini3939 0:713ef38fead1 139
okini3939 0:713ef38fead1 140 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 141 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 142 #endif
okini3939 0:713ef38fead1 143
okini3939 0:713ef38fead1 144 return; // Don't send anything
okini3939 0:713ef38fead1 145 }
okini3939 0:713ef38fead1 146
okini3939 0:713ef38fead1 147 if (type <= PitchBend) {
okini3939 0:713ef38fead1 148 // Channel messages
okini3939 0:713ef38fead1 149
okini3939 0:713ef38fead1 150 // Protection: remove MSBs on data
okini3939 0:713ef38fead1 151 data1 &= 0x7F;
okini3939 0:713ef38fead1 152 data2 &= 0x7F;
okini3939 0:713ef38fead1 153
okini3939 0:713ef38fead1 154 byte statusbyte = genstatus(type,channel);
okini3939 0:713ef38fead1 155
okini3939 0:713ef38fead1 156 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 157 // Check Running Status
okini3939 0:713ef38fead1 158 if (mRunningStatus_TX != statusbyte) {
okini3939 0:713ef38fead1 159 // New message, memorise and send header
okini3939 0:713ef38fead1 160 mRunningStatus_TX = statusbyte;
okini3939 0:713ef38fead1 161 USE_SERIAL_PORT.putc(mRunningStatus_TX);
okini3939 0:713ef38fead1 162 }
okini3939 0:713ef38fead1 163 #else
okini3939 0:713ef38fead1 164 // Don't care about running status, send the Control byte.
okini3939 0:713ef38fead1 165 USE_SERIAL_PORT.putc(statusbyte);
okini3939 0:713ef38fead1 166 #endif
okini3939 0:713ef38fead1 167
okini3939 0:713ef38fead1 168 // Then send data
okini3939 0:713ef38fead1 169 USE_SERIAL_PORT.putc(data1);
okini3939 0:713ef38fead1 170 if (type != ProgramChange && type != AfterTouchChannel) {
okini3939 0:713ef38fead1 171 USE_SERIAL_PORT.putc(data2);
okini3939 0:713ef38fead1 172 }
okini3939 0:713ef38fead1 173 return;
okini3939 0:713ef38fead1 174 }
okini3939 0:713ef38fead1 175 if (type >= TuneRequest && type <= SystemReset) {
okini3939 0:713ef38fead1 176 // System Real-time and 1 byte.
okini3939 0:713ef38fead1 177 sendRealTime(type);
okini3939 0:713ef38fead1 178 }
okini3939 0:713ef38fead1 179
okini3939 0:713ef38fead1 180 }
okini3939 0:713ef38fead1 181
okini3939 0:713ef38fead1 182
okini3939 0:713ef38fead1 183 /*! \brief Send a Note On message
okini3939 0:713ef38fead1 184 \param NoteNumber Pitch value in the MIDI format (0 to 127). Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html\n
okini3939 0:713ef38fead1 185 \param Velocity Note attack velocity (0 to 127). A NoteOn with 0 velocity is considered as a NoteOff.
okini3939 0:713ef38fead1 186 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 187 */
okini3939 0:713ef38fead1 188 void MIDI::sendNoteOn(byte NoteNumber,
okini3939 0:713ef38fead1 189 byte Velocity,
okini3939 0:713ef38fead1 190 byte Channel)
okini3939 0:713ef38fead1 191 {
okini3939 0:713ef38fead1 192
okini3939 0:713ef38fead1 193 send(NoteOn,NoteNumber,Velocity,Channel);
okini3939 0:713ef38fead1 194
okini3939 0:713ef38fead1 195 }
okini3939 0:713ef38fead1 196
okini3939 0:713ef38fead1 197
okini3939 0:713ef38fead1 198 /*! \brief Send a Note Off message (a real Note Off, not a Note On with null velocity)
okini3939 0:713ef38fead1 199 \param NoteNumber Pitch value in the MIDI format (0 to 127). Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html\n
okini3939 0:713ef38fead1 200 \param Velocity Release velocity (0 to 127).
okini3939 0:713ef38fead1 201 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 202 */
okini3939 0:713ef38fead1 203 void MIDI::sendNoteOff(byte NoteNumber,
okini3939 0:713ef38fead1 204 byte Velocity,
okini3939 0:713ef38fead1 205 byte Channel)
okini3939 0:713ef38fead1 206 {
okini3939 0:713ef38fead1 207
okini3939 0:713ef38fead1 208 send(NoteOff,NoteNumber,Velocity,Channel);
okini3939 0:713ef38fead1 209
okini3939 0:713ef38fead1 210 }
okini3939 0:713ef38fead1 211
okini3939 0:713ef38fead1 212
okini3939 0:713ef38fead1 213 /*! \brief Send a Program Change message
okini3939 0:713ef38fead1 214 \param ProgramNumber The Program to select (0 to 127).
okini3939 0:713ef38fead1 215 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 216 */
okini3939 0:713ef38fead1 217 void MIDI::sendProgramChange(byte ProgramNumber,
okini3939 0:713ef38fead1 218 byte Channel)
okini3939 0:713ef38fead1 219 {
okini3939 0:713ef38fead1 220
okini3939 0:713ef38fead1 221 send(ProgramChange,ProgramNumber,0,Channel);
okini3939 0:713ef38fead1 222
okini3939 0:713ef38fead1 223 }
okini3939 0:713ef38fead1 224
okini3939 0:713ef38fead1 225
okini3939 0:713ef38fead1 226 /*! \brief Send a Control Change message
okini3939 0:713ef38fead1 227 \param ControlNumber The controller number (0 to 127). See the detailed description here: http://www.somascape.org/midi/tech/spec.html#ctrlnums
okini3939 0:713ef38fead1 228 \param ControlValue The value for the specified controller (0 to 127).
okini3939 0:713ef38fead1 229 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 230 */
okini3939 0:713ef38fead1 231 void MIDI::sendControlChange(byte ControlNumber,
okini3939 0:713ef38fead1 232 byte ControlValue,
okini3939 0:713ef38fead1 233 byte Channel)
okini3939 0:713ef38fead1 234 {
okini3939 0:713ef38fead1 235
okini3939 0:713ef38fead1 236 send(ControlChange,ControlNumber,ControlValue,Channel);
okini3939 0:713ef38fead1 237
okini3939 0:713ef38fead1 238 }
okini3939 0:713ef38fead1 239
okini3939 0:713ef38fead1 240
okini3939 0:713ef38fead1 241 /*! \brief Send a Polyphonic AfterTouch message (applies to only one specified note)
okini3939 0:713ef38fead1 242 \param NoteNumber The note to apply AfterTouch to (0 to 127).
okini3939 0:713ef38fead1 243 \param Pressure The amount of AfterTouch to apply (0 to 127).
okini3939 0:713ef38fead1 244 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 245 */
okini3939 0:713ef38fead1 246 void MIDI::sendPolyPressure(byte NoteNumber,
okini3939 0:713ef38fead1 247 byte Pressure,
okini3939 0:713ef38fead1 248 byte Channel)
okini3939 0:713ef38fead1 249 {
okini3939 0:713ef38fead1 250
okini3939 0:713ef38fead1 251 send(AfterTouchPoly,NoteNumber,Pressure,Channel);
okini3939 0:713ef38fead1 252
okini3939 0:713ef38fead1 253 }
okini3939 0:713ef38fead1 254
okini3939 0:713ef38fead1 255
okini3939 0:713ef38fead1 256 /*! \brief Send a MonoPhonic AfterTouch message (applies to all notes)
okini3939 0:713ef38fead1 257 \param Pressure The amount of AfterTouch to apply to all notes.
okini3939 0:713ef38fead1 258 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 259 */
okini3939 0:713ef38fead1 260 void MIDI::sendAfterTouch(byte Pressure,
okini3939 0:713ef38fead1 261 byte Channel)
okini3939 0:713ef38fead1 262 {
okini3939 0:713ef38fead1 263
okini3939 0:713ef38fead1 264 send(AfterTouchChannel,Pressure,0,Channel);
okini3939 0:713ef38fead1 265
okini3939 0:713ef38fead1 266 }
okini3939 0:713ef38fead1 267
okini3939 0:713ef38fead1 268
okini3939 0:713ef38fead1 269 /*! \brief Send a Pitch Bend message using a signed integer value.
okini3939 0:713ef38fead1 270 \param PitchValue The amount of bend to send (in a signed integer format), between -8192 (maximum downwards bend) and 8191 (max upwards bend), center value is 0.
okini3939 0:713ef38fead1 271 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 272 */
okini3939 0:713ef38fead1 273 void MIDI::sendPitchBend(int PitchValue,
okini3939 0:713ef38fead1 274 byte Channel)
okini3939 0:713ef38fead1 275 {
okini3939 0:713ef38fead1 276
okini3939 0:713ef38fead1 277 unsigned int bend = PitchValue + 8192;
okini3939 0:713ef38fead1 278 sendPitchBend(bend,Channel);
okini3939 0:713ef38fead1 279
okini3939 0:713ef38fead1 280 }
okini3939 0:713ef38fead1 281
okini3939 0:713ef38fead1 282
okini3939 0:713ef38fead1 283 /*! \brief Send a Pitch Bend message using an unsigned integer value.
okini3939 0:713ef38fead1 284 \param PitchValue The amount of bend to send (in a signed integer format), between 0 (maximum downwards bend) and 16383 (max upwards bend), center value is 8192.
okini3939 0:713ef38fead1 285 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 286 */
okini3939 0:713ef38fead1 287 void MIDI::sendPitchBend(unsigned int PitchValue,
okini3939 0:713ef38fead1 288 byte Channel)
okini3939 0:713ef38fead1 289 {
okini3939 0:713ef38fead1 290
okini3939 0:713ef38fead1 291 send(PitchBend,(PitchValue & 0x7F),(PitchValue >> 7) & 0x7F,Channel);
okini3939 0:713ef38fead1 292
okini3939 0:713ef38fead1 293 }
okini3939 0:713ef38fead1 294
okini3939 0:713ef38fead1 295
okini3939 0:713ef38fead1 296 /*! \brief Send a Pitch Bend message using a floating point value.
okini3939 0:713ef38fead1 297 \param PitchValue The amount of bend to send (in a floating point format), between -1.0f (maximum downwards bend) and +1.0f (max upwards bend), center value is 0.0f.
okini3939 0:713ef38fead1 298 \param Channel The channel on which the message will be sent (1 to 16).
okini3939 0:713ef38fead1 299 */
okini3939 0:713ef38fead1 300 void MIDI::sendPitchBend(double PitchValue,
okini3939 0:713ef38fead1 301 byte Channel)
okini3939 0:713ef38fead1 302 {
okini3939 0:713ef38fead1 303
okini3939 0:713ef38fead1 304 unsigned int pitchval = (PitchValue+1.f)*8192;
okini3939 0:713ef38fead1 305 if (pitchval > 16383) pitchval = 16383; // overflow protection
okini3939 0:713ef38fead1 306 sendPitchBend(pitchval,Channel);
okini3939 0:713ef38fead1 307
okini3939 0:713ef38fead1 308 }
okini3939 0:713ef38fead1 309
okini3939 0:713ef38fead1 310
okini3939 0:713ef38fead1 311 /*! \brief Generate and send a System Exclusive frame.
okini3939 0:713ef38fead1 312 \param length The size of the array to send
okini3939 0:713ef38fead1 313 \param array The byte array containing the data to send
okini3939 0:713ef38fead1 314 \param ArrayContainsBoundaries When set to 'true', 0xF0 & 0xF7 bytes (start & stop SysEx) will NOT be sent (and therefore must be included in the array).
okini3939 0:713ef38fead1 315 default value is set to 'false' for compatibility with previous versions of the library.
okini3939 0:713ef38fead1 316 */
okini3939 0:713ef38fead1 317 void MIDI::sendSysEx(int length,
okini3939 0:713ef38fead1 318 const byte *const array,
okini3939 0:713ef38fead1 319 bool ArrayContainsBoundaries)
okini3939 0:713ef38fead1 320 {
okini3939 0:713ef38fead1 321
okini3939 0:713ef38fead1 322 if (ArrayContainsBoundaries == false) {
okini3939 0:713ef38fead1 323
okini3939 0:713ef38fead1 324 USE_SERIAL_PORT.putc(0xF0);
okini3939 0:713ef38fead1 325
okini3939 0:713ef38fead1 326 for (int i=0;i<length;++i) {
okini3939 0:713ef38fead1 327
okini3939 0:713ef38fead1 328 USE_SERIAL_PORT.putc(array[i]);
okini3939 0:713ef38fead1 329
okini3939 0:713ef38fead1 330 }
okini3939 0:713ef38fead1 331
okini3939 0:713ef38fead1 332 USE_SERIAL_PORT.putc(0xF7);
okini3939 0:713ef38fead1 333
okini3939 0:713ef38fead1 334 }
okini3939 0:713ef38fead1 335 else {
okini3939 0:713ef38fead1 336
okini3939 0:713ef38fead1 337 for (int i=0;i<length;++i) {
okini3939 0:713ef38fead1 338
okini3939 0:713ef38fead1 339 USE_SERIAL_PORT.putc(array[i]);
okini3939 0:713ef38fead1 340
okini3939 0:713ef38fead1 341 }
okini3939 0:713ef38fead1 342
okini3939 0:713ef38fead1 343 }
okini3939 0:713ef38fead1 344
okini3939 0:713ef38fead1 345 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 346 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 347 #endif
okini3939 0:713ef38fead1 348
okini3939 0:713ef38fead1 349 }
okini3939 0:713ef38fead1 350
okini3939 0:713ef38fead1 351
okini3939 0:713ef38fead1 352 /*! \brief Send a Tune Request message.
okini3939 0:713ef38fead1 353
okini3939 0:713ef38fead1 354 When a MIDI unit receives this message, it should tune its oscillators (if equipped with any)
okini3939 0:713ef38fead1 355 */
okini3939 0:713ef38fead1 356 void MIDI::sendTuneRequest()
okini3939 0:713ef38fead1 357 {
okini3939 0:713ef38fead1 358
okini3939 0:713ef38fead1 359 sendRealTime(TuneRequest);
okini3939 0:713ef38fead1 360
okini3939 0:713ef38fead1 361 }
okini3939 0:713ef38fead1 362
okini3939 0:713ef38fead1 363
okini3939 0:713ef38fead1 364 /*! \brief Send a MIDI Time Code Quarter Frame.
okini3939 0:713ef38fead1 365
okini3939 0:713ef38fead1 366 See MIDI Specification for more information.
okini3939 0:713ef38fead1 367 \param TypeNibble MTC type
okini3939 0:713ef38fead1 368 \param ValuesNibble MTC data
okini3939 0:713ef38fead1 369 */
okini3939 0:713ef38fead1 370 void MIDI::sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble)
okini3939 0:713ef38fead1 371 {
okini3939 0:713ef38fead1 372
okini3939 0:713ef38fead1 373 byte data = ( ((TypeNibble & 0x07) << 4) | (ValuesNibble & 0x0F) );
okini3939 0:713ef38fead1 374 sendTimeCodeQuarterFrame(data);
okini3939 0:713ef38fead1 375
okini3939 0:713ef38fead1 376 }
okini3939 0:713ef38fead1 377
okini3939 0:713ef38fead1 378
okini3939 0:713ef38fead1 379 /*! \brief Send a MIDI Time Code Quarter Frame.
okini3939 0:713ef38fead1 380
okini3939 0:713ef38fead1 381 See MIDI Specification for more information.
okini3939 0:713ef38fead1 382 \param data if you want to encode directly the nibbles in your program, you can send the byte here.
okini3939 0:713ef38fead1 383 */
okini3939 0:713ef38fead1 384 void MIDI::sendTimeCodeQuarterFrame(byte data)
okini3939 0:713ef38fead1 385 {
okini3939 0:713ef38fead1 386
okini3939 0:713ef38fead1 387 USE_SERIAL_PORT.putc((byte)TimeCodeQuarterFrame);
okini3939 0:713ef38fead1 388 USE_SERIAL_PORT.putc(data);
okini3939 0:713ef38fead1 389
okini3939 0:713ef38fead1 390 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 391 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 392 #endif
okini3939 0:713ef38fead1 393
okini3939 0:713ef38fead1 394 }
okini3939 0:713ef38fead1 395
okini3939 0:713ef38fead1 396
okini3939 0:713ef38fead1 397 /*! \brief Send a Song Position Pointer message.
okini3939 0:713ef38fead1 398 \param Beats The number of beats since the start of the song.
okini3939 0:713ef38fead1 399 */
okini3939 0:713ef38fead1 400 void MIDI::sendSongPosition(unsigned int Beats)
okini3939 0:713ef38fead1 401 {
okini3939 0:713ef38fead1 402
okini3939 0:713ef38fead1 403 USE_SERIAL_PORT.putc((byte)SongPosition);
okini3939 0:713ef38fead1 404 USE_SERIAL_PORT.putc(Beats & 0x7F);
okini3939 0:713ef38fead1 405 USE_SERIAL_PORT.putc((Beats >> 7) & 0x7F);
okini3939 0:713ef38fead1 406
okini3939 0:713ef38fead1 407 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 408 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 409 #endif
okini3939 0:713ef38fead1 410
okini3939 0:713ef38fead1 411 }
okini3939 0:713ef38fead1 412
okini3939 0:713ef38fead1 413
okini3939 0:713ef38fead1 414 /*! \brief Send a Song Select message */
okini3939 0:713ef38fead1 415 void MIDI::sendSongSelect(byte SongNumber)
okini3939 0:713ef38fead1 416 {
okini3939 0:713ef38fead1 417
okini3939 0:713ef38fead1 418 USE_SERIAL_PORT.putc((byte)SongSelect);
okini3939 0:713ef38fead1 419 USE_SERIAL_PORT.putc(SongNumber & 0x7F);
okini3939 0:713ef38fead1 420
okini3939 0:713ef38fead1 421 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 422 mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 423 #endif
okini3939 0:713ef38fead1 424
okini3939 0:713ef38fead1 425 }
okini3939 0:713ef38fead1 426
okini3939 0:713ef38fead1 427
okini3939 0:713ef38fead1 428 /*! \brief Send a Real Time (one byte) message.
okini3939 0:713ef38fead1 429
okini3939 0:713ef38fead1 430 \param Type The available Real Time types are: Start, Stop, Continue, Clock, ActiveSensing and SystemReset.
okini3939 0:713ef38fead1 431 You can also send a Tune Request with this method.
okini3939 0:713ef38fead1 432 @see kMIDIType
okini3939 0:713ef38fead1 433 */
okini3939 0:713ef38fead1 434 void MIDI::sendRealTime(kMIDIType Type)
okini3939 0:713ef38fead1 435 {
okini3939 0:713ef38fead1 436 switch (Type) {
okini3939 0:713ef38fead1 437 case TuneRequest: // Not really real-time, but one byte anyway.
okini3939 0:713ef38fead1 438 case Clock:
okini3939 0:713ef38fead1 439 case Start:
okini3939 0:713ef38fead1 440 case Stop:
okini3939 0:713ef38fead1 441 case Continue:
okini3939 0:713ef38fead1 442 case ActiveSensing:
okini3939 0:713ef38fead1 443 case SystemReset:
okini3939 0:713ef38fead1 444 USE_SERIAL_PORT.putc((byte)Type);
okini3939 0:713ef38fead1 445 break;
okini3939 0:713ef38fead1 446 default:
okini3939 0:713ef38fead1 447 // Invalid Real Time marker
okini3939 0:713ef38fead1 448 break;
okini3939 0:713ef38fead1 449 }
okini3939 0:713ef38fead1 450
okini3939 0:713ef38fead1 451 // Do not cancel Running Status for real-time messages as they can be interleaved within any message.
okini3939 0:713ef38fead1 452 // Though, TuneRequest can be sent here, and as it is a System Common message, it must reset Running Status.
okini3939 0:713ef38fead1 453 #if USE_RUNNING_STATUS
okini3939 0:713ef38fead1 454 if (Type == TuneRequest) mRunningStatus_TX = InvalidType;
okini3939 0:713ef38fead1 455 #endif
okini3939 0:713ef38fead1 456
okini3939 0:713ef38fead1 457 }
okini3939 0:713ef38fead1 458
okini3939 0:713ef38fead1 459 #endif // COMPILE_MIDI_OUT
okini3939 0:713ef38fead1 460
okini3939 0:713ef38fead1 461
okini3939 0:713ef38fead1 462
okini3939 0:713ef38fead1 463 #if COMPILE_MIDI_IN
okini3939 0:713ef38fead1 464
okini3939 0:713ef38fead1 465 /*! \brief Read a MIDI message from the serial port using the main input channel (see setInputChannel() for reference).
okini3939 0:713ef38fead1 466
okini3939 0:713ef38fead1 467 Returned value: true if any valid message has been stored in the structure, false if not.
okini3939 0:713ef38fead1 468 A valid message is a message that matches the input channel. \n\n
okini3939 0:713ef38fead1 469 If the Thru is enabled and the messages matches the filter, it is sent back on the MIDI output.
okini3939 0:713ef38fead1 470 */
okini3939 0:713ef38fead1 471 bool MIDI::read()
okini3939 0:713ef38fead1 472 {
okini3939 0:713ef38fead1 473
okini3939 0:713ef38fead1 474 return read(mInputChannel);
okini3939 0:713ef38fead1 475
okini3939 0:713ef38fead1 476 }
okini3939 0:713ef38fead1 477
okini3939 0:713ef38fead1 478
okini3939 0:713ef38fead1 479 /*! \brief Reading/thru-ing method, the same as read() with a given input channel to read on. */
okini3939 0:713ef38fead1 480 bool MIDI::read(const byte inChannel)
okini3939 0:713ef38fead1 481 {
okini3939 0:713ef38fead1 482
okini3939 0:713ef38fead1 483 if (inChannel >= MIDI_CHANNEL_OFF) return false; // MIDI Input disabled.
okini3939 0:713ef38fead1 484
okini3939 0:713ef38fead1 485 if (parse(inChannel)) {
okini3939 0:713ef38fead1 486
okini3939 0:713ef38fead1 487 if (input_filter(inChannel)) {
okini3939 0:713ef38fead1 488
okini3939 0:713ef38fead1 489 #if (COMPILE_MIDI_OUT && COMPILE_MIDI_THRU)
okini3939 0:713ef38fead1 490 thru_filter(inChannel);
okini3939 0:713ef38fead1 491 #endif
okini3939 0:713ef38fead1 492
okini3939 0:713ef38fead1 493 #if USE_CALLBACKS
okini3939 0:713ef38fead1 494 launchCallback();
okini3939 0:713ef38fead1 495 #endif
okini3939 0:713ef38fead1 496
okini3939 0:713ef38fead1 497 return true;
okini3939 0:713ef38fead1 498 }
okini3939 0:713ef38fead1 499
okini3939 0:713ef38fead1 500 }
okini3939 0:713ef38fead1 501
okini3939 0:713ef38fead1 502 return false;
okini3939 0:713ef38fead1 503
okini3939 0:713ef38fead1 504 }
okini3939 0:713ef38fead1 505
okini3939 0:713ef38fead1 506
okini3939 0:713ef38fead1 507 // Private method: MIDI parser
okini3939 0:713ef38fead1 508 bool MIDI::parse(byte inChannel)
okini3939 0:713ef38fead1 509 {
okini3939 0:713ef38fead1 510
okini3939 0:713ef38fead1 511 const int bytes_available = USE_SERIAL_PORT.readable();
okini3939 0:713ef38fead1 512
okini3939 0:713ef38fead1 513 if (bytes_available <= 0) {
okini3939 0:713ef38fead1 514 // No data available.
okini3939 0:713ef38fead1 515 return false;
okini3939 0:713ef38fead1 516 }
okini3939 0:713ef38fead1 517
okini3939 0:713ef38fead1 518 // If the buffer is full -> Don't Panic! Call the Vogons to destroy it.
okini3939 0:713ef38fead1 519 if (bytes_available == 128) {
okini3939 0:713ef38fead1 520 // USE_SERIAL_PORT.flush();
okini3939 0:713ef38fead1 521 }
okini3939 0:713ef38fead1 522 else {
okini3939 0:713ef38fead1 523
okini3939 0:713ef38fead1 524 /* Parsing algorithm:
okini3939 0:713ef38fead1 525 Get a byte from the serial buffer.
okini3939 0:713ef38fead1 526 * If there is no pending message to be recomposed, start a new one.
okini3939 0:713ef38fead1 527 - Find type and channel (if pertinent)
okini3939 0:713ef38fead1 528 - Look for other bytes in buffer, call parser recursively, until the message is assembled or the buffer is empty.
okini3939 0:713ef38fead1 529 * Else, add the extracted byte to the pending message, and check validity. When the message is done, store it.
okini3939 0:713ef38fead1 530 */
okini3939 0:713ef38fead1 531
okini3939 0:713ef38fead1 532
okini3939 0:713ef38fead1 533 const byte extracted = USE_SERIAL_PORT.getc();
okini3939 0:713ef38fead1 534
okini3939 0:713ef38fead1 535 if (mPendingMessageIndex == 0) { // Start a new pending message
okini3939 0:713ef38fead1 536 mPendingMessage[0] = extracted;
okini3939 0:713ef38fead1 537
okini3939 0:713ef38fead1 538 // Check for running status first
okini3939 0:713ef38fead1 539 switch (getTypeFromStatusByte(mRunningStatus_RX)) {
okini3939 0:713ef38fead1 540 // Only these types allow Running Status:
okini3939 0:713ef38fead1 541 case NoteOff:
okini3939 0:713ef38fead1 542 case NoteOn:
okini3939 0:713ef38fead1 543 case AfterTouchPoly:
okini3939 0:713ef38fead1 544 case ControlChange:
okini3939 0:713ef38fead1 545 case ProgramChange:
okini3939 0:713ef38fead1 546 case AfterTouchChannel:
okini3939 0:713ef38fead1 547 case PitchBend:
okini3939 0:713ef38fead1 548
okini3939 0:713ef38fead1 549 // If the status byte is not received, prepend it to the pending message
okini3939 0:713ef38fead1 550 if (extracted < 0x80) {
okini3939 0:713ef38fead1 551 mPendingMessage[0] = mRunningStatus_RX;
okini3939 0:713ef38fead1 552 mPendingMessage[1] = extracted;
okini3939 0:713ef38fead1 553 mPendingMessageIndex = 1;
okini3939 0:713ef38fead1 554 }
okini3939 0:713ef38fead1 555 // Else: well, we received another status byte, so the running status does not apply here.
okini3939 0:713ef38fead1 556 // It will be updated upon completion of this message.
okini3939 0:713ef38fead1 557
okini3939 0:713ef38fead1 558 break;
okini3939 0:713ef38fead1 559
okini3939 0:713ef38fead1 560 default:
okini3939 0:713ef38fead1 561 // No running status
okini3939 0:713ef38fead1 562 break;
okini3939 0:713ef38fead1 563 }
okini3939 0:713ef38fead1 564
okini3939 0:713ef38fead1 565
okini3939 0:713ef38fead1 566 switch (getTypeFromStatusByte(mPendingMessage[0])) {
okini3939 0:713ef38fead1 567
okini3939 0:713ef38fead1 568 // 1 byte messages
okini3939 0:713ef38fead1 569 case Start:
okini3939 0:713ef38fead1 570 case Continue:
okini3939 0:713ef38fead1 571 case Stop:
okini3939 0:713ef38fead1 572 case Clock:
okini3939 0:713ef38fead1 573 case ActiveSensing:
okini3939 0:713ef38fead1 574 case SystemReset:
okini3939 0:713ef38fead1 575 case TuneRequest:
okini3939 0:713ef38fead1 576 // Handle the message type directly here.
okini3939 0:713ef38fead1 577 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
okini3939 0:713ef38fead1 578 mMessage.channel = 0;
okini3939 0:713ef38fead1 579 mMessage.data1 = 0;
okini3939 0:713ef38fead1 580 mMessage.data2 = 0;
okini3939 0:713ef38fead1 581 mMessage.valid = true;
okini3939 0:713ef38fead1 582
okini3939 0:713ef38fead1 583 // \fix Running Status broken when receiving Clock messages.
okini3939 0:713ef38fead1 584 // Do not reset all input attributes, Running Status must remain unchanged.
okini3939 0:713ef38fead1 585 //reset_input_attributes();
okini3939 0:713ef38fead1 586
okini3939 0:713ef38fead1 587 // We still need to reset these
okini3939 0:713ef38fead1 588 mPendingMessageIndex = 0;
okini3939 0:713ef38fead1 589 mPendingMessageExpectedLenght = 0;
okini3939 0:713ef38fead1 590
okini3939 0:713ef38fead1 591 return true;
okini3939 0:713ef38fead1 592
okini3939 0:713ef38fead1 593 // 2 bytes messages
okini3939 0:713ef38fead1 594 case ProgramChange:
okini3939 0:713ef38fead1 595 case AfterTouchChannel:
okini3939 0:713ef38fead1 596 case TimeCodeQuarterFrame:
okini3939 0:713ef38fead1 597 case SongSelect:
okini3939 0:713ef38fead1 598 mPendingMessageExpectedLenght = 2;
okini3939 0:713ef38fead1 599 break;
okini3939 0:713ef38fead1 600
okini3939 0:713ef38fead1 601 // 3 bytes messages
okini3939 0:713ef38fead1 602 case NoteOn:
okini3939 0:713ef38fead1 603 case NoteOff:
okini3939 0:713ef38fead1 604 case ControlChange:
okini3939 0:713ef38fead1 605 case PitchBend:
okini3939 0:713ef38fead1 606 case AfterTouchPoly:
okini3939 0:713ef38fead1 607 case SongPosition:
okini3939 0:713ef38fead1 608 mPendingMessageExpectedLenght = 3;
okini3939 0:713ef38fead1 609 break;
okini3939 0:713ef38fead1 610
okini3939 0:713ef38fead1 611 case SystemExclusive:
okini3939 0:713ef38fead1 612 mPendingMessageExpectedLenght = MIDI_SYSEX_ARRAY_SIZE; // As the message can be any lenght between 3 and MIDI_SYSEX_ARRAY_SIZE bytes
okini3939 0:713ef38fead1 613 mRunningStatus_RX = InvalidType;
okini3939 0:713ef38fead1 614 break;
okini3939 0:713ef38fead1 615
okini3939 0:713ef38fead1 616 case InvalidType:
okini3939 0:713ef38fead1 617 default:
okini3939 0:713ef38fead1 618 // This is obviously wrong. Let's get the hell out'a here.
okini3939 0:713ef38fead1 619 reset_input_attributes();
okini3939 0:713ef38fead1 620 return false;
okini3939 0:713ef38fead1 621 }
okini3939 0:713ef38fead1 622
okini3939 0:713ef38fead1 623 // Then update the index of the pending message.
okini3939 0:713ef38fead1 624 mPendingMessageIndex++;
okini3939 0:713ef38fead1 625
okini3939 0:713ef38fead1 626 #if USE_1BYTE_PARSING
okini3939 0:713ef38fead1 627 // Message is not complete.
okini3939 0:713ef38fead1 628 return false;
okini3939 0:713ef38fead1 629 #else
okini3939 0:713ef38fead1 630 // Call the parser recursively
okini3939 0:713ef38fead1 631 // to parse the rest of the message.
okini3939 0:713ef38fead1 632 return parse(inChannel);
okini3939 0:713ef38fead1 633 #endif
okini3939 0:713ef38fead1 634
okini3939 0:713ef38fead1 635 }
okini3939 0:713ef38fead1 636 else {
okini3939 0:713ef38fead1 637
okini3939 0:713ef38fead1 638 // First, test if this is a status byte
okini3939 0:713ef38fead1 639 if (extracted >= 0x80) {
okini3939 0:713ef38fead1 640
okini3939 0:713ef38fead1 641 // Reception of status bytes in the middle of an uncompleted message
okini3939 0:713ef38fead1 642 // are allowed only for interleaved Real Time message or EOX
okini3939 0:713ef38fead1 643 switch (extracted) {
okini3939 0:713ef38fead1 644 case Clock:
okini3939 0:713ef38fead1 645 case Start:
okini3939 0:713ef38fead1 646 case Continue:
okini3939 0:713ef38fead1 647 case Stop:
okini3939 0:713ef38fead1 648 case ActiveSensing:
okini3939 0:713ef38fead1 649 case SystemReset:
okini3939 0:713ef38fead1 650
okini3939 0:713ef38fead1 651 /*
okini3939 0:713ef38fead1 652 This is tricky. Here we will have to extract the one-byte message,
okini3939 0:713ef38fead1 653 pass it to the structure for being read outside the MIDI class,
okini3939 0:713ef38fead1 654 and recompose the message it was interleaved into.
okini3939 0:713ef38fead1 655
okini3939 0:713ef38fead1 656 Oh, and without killing the running status..
okini3939 0:713ef38fead1 657
okini3939 0:713ef38fead1 658 This is done by leaving the pending message as is, it will be completed on next calls.
okini3939 0:713ef38fead1 659 */
okini3939 0:713ef38fead1 660
okini3939 0:713ef38fead1 661 mMessage.type = (kMIDIType)extracted;
okini3939 0:713ef38fead1 662 mMessage.data1 = 0;
okini3939 0:713ef38fead1 663 mMessage.data2 = 0;
okini3939 0:713ef38fead1 664 mMessage.channel = 0;
okini3939 0:713ef38fead1 665 mMessage.valid = true;
okini3939 0:713ef38fead1 666 return true;
okini3939 0:713ef38fead1 667
okini3939 0:713ef38fead1 668 // End of Exclusive
okini3939 0:713ef38fead1 669 case 0xF7:
okini3939 0:713ef38fead1 670 if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
okini3939 0:713ef38fead1 671
okini3939 0:713ef38fead1 672 // Store System Exclusive array in midimsg structure
okini3939 0:713ef38fead1 673 for (byte i=0;i<MIDI_SYSEX_ARRAY_SIZE;i++) {
okini3939 0:713ef38fead1 674 mMessage.sysex_array[i] = mPendingMessage[i];
okini3939 0:713ef38fead1 675 }
okini3939 0:713ef38fead1 676
okini3939 0:713ef38fead1 677 mMessage.type = SystemExclusive;
okini3939 0:713ef38fead1 678
okini3939 0:713ef38fead1 679 // Get length
okini3939 0:713ef38fead1 680 mMessage.data1 = (mPendingMessageIndex+1) & 0xFF;
okini3939 0:713ef38fead1 681 mMessage.data2 = (mPendingMessageIndex+1) >> 8;
okini3939 0:713ef38fead1 682
okini3939 0:713ef38fead1 683 mMessage.channel = 0;
okini3939 0:713ef38fead1 684 mMessage.valid = true;
okini3939 0:713ef38fead1 685
okini3939 0:713ef38fead1 686 reset_input_attributes();
okini3939 0:713ef38fead1 687
okini3939 0:713ef38fead1 688 return true;
okini3939 0:713ef38fead1 689 }
okini3939 0:713ef38fead1 690 else {
okini3939 0:713ef38fead1 691 // Well well well.. error.
okini3939 0:713ef38fead1 692 reset_input_attributes();
okini3939 0:713ef38fead1 693 return false;
okini3939 0:713ef38fead1 694 }
okini3939 0:713ef38fead1 695
okini3939 0:713ef38fead1 696 default:
okini3939 0:713ef38fead1 697 break;
okini3939 0:713ef38fead1 698 }
okini3939 0:713ef38fead1 699
okini3939 0:713ef38fead1 700
okini3939 0:713ef38fead1 701
okini3939 0:713ef38fead1 702 }
okini3939 0:713ef38fead1 703
okini3939 0:713ef38fead1 704
okini3939 0:713ef38fead1 705 // Add extracted data byte to pending message
okini3939 0:713ef38fead1 706 mPendingMessage[mPendingMessageIndex] = extracted;
okini3939 0:713ef38fead1 707
okini3939 0:713ef38fead1 708
okini3939 0:713ef38fead1 709 // Now we are going to check if we have reached the end of the message
okini3939 0:713ef38fead1 710 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght-1)) {
okini3939 0:713ef38fead1 711
okini3939 0:713ef38fead1 712 // "FML" case: fall down here with an overflown SysEx..
okini3939 0:713ef38fead1 713 // This means we received the last possible data byte that can fit the buffer.
okini3939 0:713ef38fead1 714 // If this happens, try increasing MIDI_SYSEX_ARRAY_SIZE.
okini3939 0:713ef38fead1 715 if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
okini3939 0:713ef38fead1 716 reset_input_attributes();
okini3939 0:713ef38fead1 717 return false;
okini3939 0:713ef38fead1 718 }
okini3939 0:713ef38fead1 719
okini3939 0:713ef38fead1 720
okini3939 0:713ef38fead1 721 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
okini3939 0:713ef38fead1 722 mMessage.channel = (mPendingMessage[0] & 0x0F)+1; // Don't check if it is a Channel Message
okini3939 0:713ef38fead1 723
okini3939 0:713ef38fead1 724 mMessage.data1 = mPendingMessage[1];
okini3939 0:713ef38fead1 725
okini3939 0:713ef38fead1 726 // Save data2 only if applicable
okini3939 0:713ef38fead1 727 if (mPendingMessageExpectedLenght == 3) mMessage.data2 = mPendingMessage[2];
okini3939 0:713ef38fead1 728 else mMessage.data2 = 0;
okini3939 0:713ef38fead1 729
okini3939 0:713ef38fead1 730 // Reset local variables
okini3939 0:713ef38fead1 731 mPendingMessageIndex = 0;
okini3939 0:713ef38fead1 732 mPendingMessageExpectedLenght = 0;
okini3939 0:713ef38fead1 733
okini3939 0:713ef38fead1 734 mMessage.valid = true;
okini3939 0:713ef38fead1 735
okini3939 0:713ef38fead1 736 // Activate running status (if enabled for the received type)
okini3939 0:713ef38fead1 737 switch (mMessage.type) {
okini3939 0:713ef38fead1 738 case NoteOff:
okini3939 0:713ef38fead1 739 case NoteOn:
okini3939 0:713ef38fead1 740 case AfterTouchPoly:
okini3939 0:713ef38fead1 741 case ControlChange:
okini3939 0:713ef38fead1 742 case ProgramChange:
okini3939 0:713ef38fead1 743 case AfterTouchChannel:
okini3939 0:713ef38fead1 744 case PitchBend:
okini3939 0:713ef38fead1 745 // Running status enabled: store it from received message
okini3939 0:713ef38fead1 746 mRunningStatus_RX = mPendingMessage[0];
okini3939 0:713ef38fead1 747 break;
okini3939 0:713ef38fead1 748
okini3939 0:713ef38fead1 749 default:
okini3939 0:713ef38fead1 750 // No running status
okini3939 0:713ef38fead1 751 mRunningStatus_RX = InvalidType;
okini3939 0:713ef38fead1 752 break;
okini3939 0:713ef38fead1 753 }
okini3939 0:713ef38fead1 754 return true;
okini3939 0:713ef38fead1 755 }
okini3939 0:713ef38fead1 756 else {
okini3939 0:713ef38fead1 757 // Then update the index of the pending message.
okini3939 0:713ef38fead1 758 mPendingMessageIndex++;
okini3939 0:713ef38fead1 759
okini3939 0:713ef38fead1 760 #if USE_1BYTE_PARSING
okini3939 0:713ef38fead1 761 // Message is not complete.
okini3939 0:713ef38fead1 762 return false;
okini3939 0:713ef38fead1 763 #else
okini3939 0:713ef38fead1 764 // Call the parser recursively
okini3939 0:713ef38fead1 765 // to parse the rest of the message.
okini3939 0:713ef38fead1 766 return parse(inChannel);
okini3939 0:713ef38fead1 767 #endif
okini3939 0:713ef38fead1 768
okini3939 0:713ef38fead1 769 }
okini3939 0:713ef38fead1 770
okini3939 0:713ef38fead1 771 }
okini3939 0:713ef38fead1 772
okini3939 0:713ef38fead1 773 }
okini3939 0:713ef38fead1 774
okini3939 0:713ef38fead1 775 // What are our chances to fall here?
okini3939 0:713ef38fead1 776 return false;
okini3939 0:713ef38fead1 777 }
okini3939 0:713ef38fead1 778
okini3939 0:713ef38fead1 779
okini3939 0:713ef38fead1 780 // Private method: check if the received message is on the listened channel
okini3939 0:713ef38fead1 781 bool MIDI::input_filter(byte inChannel)
okini3939 0:713ef38fead1 782 {
okini3939 0:713ef38fead1 783
okini3939 0:713ef38fead1 784
okini3939 0:713ef38fead1 785 // This method handles recognition of channel (to know if the message is destinated to the Arduino)
okini3939 0:713ef38fead1 786
okini3939 0:713ef38fead1 787
okini3939 0:713ef38fead1 788 if (mMessage.type == InvalidType) return false;
okini3939 0:713ef38fead1 789
okini3939 0:713ef38fead1 790
okini3939 0:713ef38fead1 791 // First, check if the received message is Channel
okini3939 0:713ef38fead1 792 if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) {
okini3939 0:713ef38fead1 793
okini3939 0:713ef38fead1 794 // Then we need to know if we listen to it
okini3939 0:713ef38fead1 795 if ((mMessage.channel == mInputChannel) || (mInputChannel == MIDI_CHANNEL_OMNI)) {
okini3939 0:713ef38fead1 796 return true;
okini3939 0:713ef38fead1 797
okini3939 0:713ef38fead1 798 }
okini3939 0:713ef38fead1 799 else {
okini3939 0:713ef38fead1 800 // We don't listen to this channel
okini3939 0:713ef38fead1 801 return false;
okini3939 0:713ef38fead1 802 }
okini3939 0:713ef38fead1 803
okini3939 0:713ef38fead1 804 }
okini3939 0:713ef38fead1 805 else {
okini3939 0:713ef38fead1 806
okini3939 0:713ef38fead1 807 // System messages are always received
okini3939 0:713ef38fead1 808 return true;
okini3939 0:713ef38fead1 809 }
okini3939 0:713ef38fead1 810
okini3939 0:713ef38fead1 811 }
okini3939 0:713ef38fead1 812
okini3939 0:713ef38fead1 813
okini3939 0:713ef38fead1 814 // Private method: reset input attributes
okini3939 0:713ef38fead1 815 void MIDI::reset_input_attributes()
okini3939 0:713ef38fead1 816 {
okini3939 0:713ef38fead1 817
okini3939 0:713ef38fead1 818 mPendingMessageIndex = 0;
okini3939 0:713ef38fead1 819 mPendingMessageExpectedLenght = 0;
okini3939 0:713ef38fead1 820 mRunningStatus_RX = InvalidType;
okini3939 0:713ef38fead1 821
okini3939 0:713ef38fead1 822 }
okini3939 0:713ef38fead1 823
okini3939 0:713ef38fead1 824
okini3939 0:713ef38fead1 825 // Getters
okini3939 0:713ef38fead1 826 /*! \brief Get the last received message's type
okini3939 0:713ef38fead1 827
okini3939 0:713ef38fead1 828 Returns an enumerated type. @see kMIDIType
okini3939 0:713ef38fead1 829 */
okini3939 0:713ef38fead1 830 kMIDIType MIDI::getType() const
okini3939 0:713ef38fead1 831 {
okini3939 0:713ef38fead1 832
okini3939 0:713ef38fead1 833 return mMessage.type;
okini3939 0:713ef38fead1 834
okini3939 0:713ef38fead1 835 }
okini3939 0:713ef38fead1 836
okini3939 0:713ef38fead1 837
okini3939 0:713ef38fead1 838 /*! \brief Get the channel of the message stored in the structure.
okini3939 0:713ef38fead1 839
okini3939 0:713ef38fead1 840 Channel range is 1 to 16. For non-channel messages, this will return 0.
okini3939 0:713ef38fead1 841 */
okini3939 0:713ef38fead1 842 byte MIDI::getChannel() const
okini3939 0:713ef38fead1 843 {
okini3939 0:713ef38fead1 844
okini3939 0:713ef38fead1 845 return mMessage.channel;
okini3939 0:713ef38fead1 846
okini3939 0:713ef38fead1 847 }
okini3939 0:713ef38fead1 848
okini3939 0:713ef38fead1 849
okini3939 0:713ef38fead1 850 /*! \brief Get the first data byte of the last received message. */
okini3939 0:713ef38fead1 851 byte MIDI::getData1() const
okini3939 0:713ef38fead1 852 {
okini3939 0:713ef38fead1 853
okini3939 0:713ef38fead1 854 return mMessage.data1;
okini3939 0:713ef38fead1 855
okini3939 0:713ef38fead1 856 }
okini3939 0:713ef38fead1 857
okini3939 0:713ef38fead1 858
okini3939 0:713ef38fead1 859 /*! \brief Get the second data byte of the last received message. */
okini3939 0:713ef38fead1 860 byte MIDI::getData2() const
okini3939 0:713ef38fead1 861 {
okini3939 0:713ef38fead1 862
okini3939 0:713ef38fead1 863 return mMessage.data2;
okini3939 0:713ef38fead1 864
okini3939 0:713ef38fead1 865 }
okini3939 0:713ef38fead1 866
okini3939 0:713ef38fead1 867
okini3939 0:713ef38fead1 868 /*! \brief Get the System Exclusive byte array.
okini3939 0:713ef38fead1 869
okini3939 0:713ef38fead1 870 @see getSysExArrayLength to get the array's length in bytes.
okini3939 0:713ef38fead1 871 */
okini3939 0:713ef38fead1 872 const byte * MIDI::getSysExArray() const
okini3939 0:713ef38fead1 873 {
okini3939 0:713ef38fead1 874
okini3939 0:713ef38fead1 875 return mMessage.sysex_array;
okini3939 0:713ef38fead1 876
okini3939 0:713ef38fead1 877 }
okini3939 0:713ef38fead1 878
okini3939 0:713ef38fead1 879 /*! \brief Get the lenght of the System Exclusive array.
okini3939 0:713ef38fead1 880
okini3939 0:713ef38fead1 881 It is coded using data1 as LSB and data2 as MSB.
okini3939 0:713ef38fead1 882 \return The array's length, in bytes.
okini3939 0:713ef38fead1 883 */
okini3939 0:713ef38fead1 884 unsigned int MIDI::getSysExArrayLength() const
okini3939 0:713ef38fead1 885 {
okini3939 0:713ef38fead1 886
okini3939 0:713ef38fead1 887 unsigned int coded_size = ((unsigned int)(mMessage.data2) << 8) | mMessage.data1;
okini3939 0:713ef38fead1 888
okini3939 0:713ef38fead1 889 return (coded_size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : coded_size;
okini3939 0:713ef38fead1 890
okini3939 0:713ef38fead1 891 }
okini3939 0:713ef38fead1 892
okini3939 0:713ef38fead1 893
okini3939 0:713ef38fead1 894 /*! \brief Check if a valid message is stored in the structure. */
okini3939 0:713ef38fead1 895 bool MIDI::check() const
okini3939 0:713ef38fead1 896 {
okini3939 0:713ef38fead1 897
okini3939 0:713ef38fead1 898 return mMessage.valid;
okini3939 0:713ef38fead1 899
okini3939 0:713ef38fead1 900 }
okini3939 0:713ef38fead1 901
okini3939 0:713ef38fead1 902
okini3939 0:713ef38fead1 903 // Setters
okini3939 0:713ef38fead1 904 /*! \brief Set the value for the input MIDI channel
okini3939 0:713ef38fead1 905 \param Channel the channel value. Valid values are 1 to 16,
okini3939 0:713ef38fead1 906 MIDI_CHANNEL_OMNI if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable MIDI input.
okini3939 0:713ef38fead1 907 */
okini3939 0:713ef38fead1 908 void MIDI::setInputChannel(const byte Channel)
okini3939 0:713ef38fead1 909 {
okini3939 0:713ef38fead1 910
okini3939 0:713ef38fead1 911 mInputChannel = Channel;
okini3939 0:713ef38fead1 912
okini3939 0:713ef38fead1 913 }
okini3939 0:713ef38fead1 914
okini3939 0:713ef38fead1 915
okini3939 0:713ef38fead1 916 #if USE_CALLBACKS
okini3939 0:713ef38fead1 917
okini3939 0:713ef38fead1 918 void MIDI::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; }
okini3939 0:713ef38fead1 919 void MIDI::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; }
okini3939 0:713ef38fead1 920 void MIDI::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; }
okini3939 0:713ef38fead1 921 void MIDI::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; }
okini3939 0:713ef38fead1 922 void MIDI::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; }
okini3939 0:713ef38fead1 923 void MIDI::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; }
okini3939 0:713ef38fead1 924 void MIDI::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; }
okini3939 0:713ef38fead1 925 void MIDI::setHandleSystemExclusive(void (*fptr)(byte * array, byte size)) { mSystemExclusiveCallback = fptr; }
okini3939 0:713ef38fead1 926 void MIDI::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; }
okini3939 0:713ef38fead1 927 void MIDI::setHandleSongPosition(void (*fptr)(unsigned int beats)) { mSongPositionCallback = fptr; }
okini3939 0:713ef38fead1 928 void MIDI::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; }
okini3939 0:713ef38fead1 929 void MIDI::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; }
okini3939 0:713ef38fead1 930 void MIDI::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; }
okini3939 0:713ef38fead1 931 void MIDI::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; }
okini3939 0:713ef38fead1 932 void MIDI::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; }
okini3939 0:713ef38fead1 933 void MIDI::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; }
okini3939 0:713ef38fead1 934 void MIDI::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; }
okini3939 0:713ef38fead1 935 void MIDI::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; }
okini3939 0:713ef38fead1 936
okini3939 0:713ef38fead1 937
okini3939 0:713ef38fead1 938 /*! \brief Detach an external function from the given type.
okini3939 0:713ef38fead1 939
okini3939 0:713ef38fead1 940 Use this method to cancel the effects of setHandle********.
okini3939 0:713ef38fead1 941 \param Type The type of message to unbind. When a message of this type is received, no function will be called.
okini3939 0:713ef38fead1 942 */
okini3939 0:713ef38fead1 943 void MIDI::disconnectCallbackFromType(kMIDIType Type)
okini3939 0:713ef38fead1 944 {
okini3939 0:713ef38fead1 945
okini3939 0:713ef38fead1 946 switch (Type) {
okini3939 0:713ef38fead1 947 case NoteOff: mNoteOffCallback = NULL; break;
okini3939 0:713ef38fead1 948 case NoteOn: mNoteOnCallback = NULL; break;
okini3939 0:713ef38fead1 949 case AfterTouchPoly: mAfterTouchPolyCallback = NULL; break;
okini3939 0:713ef38fead1 950 case ControlChange: mControlChangeCallback = NULL; break;
okini3939 0:713ef38fead1 951 case ProgramChange: mProgramChangeCallback = NULL; break;
okini3939 0:713ef38fead1 952 case AfterTouchChannel: mAfterTouchChannelCallback = NULL; break;
okini3939 0:713ef38fead1 953 case PitchBend: mPitchBendCallback = NULL; break;
okini3939 0:713ef38fead1 954 case SystemExclusive: mSystemExclusiveCallback = NULL; break;
okini3939 0:713ef38fead1 955 case TimeCodeQuarterFrame: mTimeCodeQuarterFrameCallback = NULL; break;
okini3939 0:713ef38fead1 956 case SongPosition: mSongPositionCallback = NULL; break;
okini3939 0:713ef38fead1 957 case SongSelect: mSongSelectCallback = NULL; break;
okini3939 0:713ef38fead1 958 case TuneRequest: mTuneRequestCallback = NULL; break;
okini3939 0:713ef38fead1 959 case Clock: mClockCallback = NULL; break;
okini3939 0:713ef38fead1 960 case Start: mStartCallback = NULL; break;
okini3939 0:713ef38fead1 961 case Continue: mContinueCallback = NULL; break;
okini3939 0:713ef38fead1 962 case Stop: mStopCallback = NULL; break;
okini3939 0:713ef38fead1 963 case ActiveSensing: mActiveSensingCallback = NULL; break;
okini3939 0:713ef38fead1 964 case SystemReset: mSystemResetCallback = NULL; break;
okini3939 0:713ef38fead1 965 default:
okini3939 0:713ef38fead1 966 break;
okini3939 0:713ef38fead1 967 }
okini3939 0:713ef38fead1 968
okini3939 0:713ef38fead1 969 }
okini3939 0:713ef38fead1 970
okini3939 0:713ef38fead1 971
okini3939 0:713ef38fead1 972 // Private - launch callback function based on received type.
okini3939 0:713ef38fead1 973 void MIDI::launchCallback()
okini3939 0:713ef38fead1 974 {
okini3939 0:713ef38fead1 975
okini3939 0:713ef38fead1 976 // The order is mixed to allow frequent messages to trigger their callback faster.
okini3939 0:713ef38fead1 977
okini3939 0:713ef38fead1 978 switch (mMessage.type) {
okini3939 0:713ef38fead1 979 // Notes
okini3939 0:713ef38fead1 980 case NoteOff: if (mNoteOffCallback != NULL) mNoteOffCallback(mMessage.channel,mMessage.data1,mMessage.data2); break;
okini3939 0:713ef38fead1 981 case NoteOn: if (mNoteOnCallback != NULL) mNoteOnCallback(mMessage.channel,mMessage.data1,mMessage.data2); break;
okini3939 0:713ef38fead1 982
okini3939 0:713ef38fead1 983 // Real-time messages
okini3939 0:713ef38fead1 984 case Clock: if (mClockCallback != NULL) mClockCallback(); break;
okini3939 0:713ef38fead1 985 case Start: if (mStartCallback != NULL) mStartCallback(); break;
okini3939 0:713ef38fead1 986 case Continue: if (mContinueCallback != NULL) mContinueCallback(); break;
okini3939 0:713ef38fead1 987 case Stop: if (mStopCallback != NULL) mStopCallback(); break;
okini3939 0:713ef38fead1 988 case ActiveSensing: if (mActiveSensingCallback != NULL) mActiveSensingCallback(); break;
okini3939 0:713ef38fead1 989
okini3939 0:713ef38fead1 990 // Continuous controllers
okini3939 0:713ef38fead1 991 case ControlChange: if (mControlChangeCallback != NULL) mControlChangeCallback(mMessage.channel,mMessage.data1,mMessage.data2); break;
okini3939 0:713ef38fead1 992 case PitchBend: if (mPitchBendCallback != NULL) mPitchBendCallback(mMessage.channel,(int)((mMessage.data1 & 0x7F) | ((mMessage.data2 & 0x7F)<< 7)) - 8192); break; // TODO: check this
okini3939 0:713ef38fead1 993 case AfterTouchPoly: if (mAfterTouchPolyCallback != NULL) mAfterTouchPolyCallback(mMessage.channel,mMessage.data1,mMessage.data2); break;
okini3939 0:713ef38fead1 994 case AfterTouchChannel: if (mAfterTouchChannelCallback != NULL) mAfterTouchChannelCallback(mMessage.channel,mMessage.data1); break;
okini3939 0:713ef38fead1 995
okini3939 0:713ef38fead1 996 case ProgramChange: if (mProgramChangeCallback != NULL) mProgramChangeCallback(mMessage.channel,mMessage.data1); break;
okini3939 0:713ef38fead1 997 case SystemExclusive: if (mSystemExclusiveCallback != NULL) mSystemExclusiveCallback(mMessage.sysex_array,mMessage.data1); break;
okini3939 0:713ef38fead1 998
okini3939 0:713ef38fead1 999 // Occasional messages
okini3939 0:713ef38fead1 1000 case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != NULL) mTimeCodeQuarterFrameCallback(mMessage.data1); break;
okini3939 0:713ef38fead1 1001 case SongPosition: if (mSongPositionCallback != NULL) mSongPositionCallback((mMessage.data1 & 0x7F) | ((mMessage.data2 & 0x7F)<< 7)); break;
okini3939 0:713ef38fead1 1002 case SongSelect: if (mSongSelectCallback != NULL) mSongSelectCallback(mMessage.data1); break;
okini3939 0:713ef38fead1 1003 case TuneRequest: if (mTuneRequestCallback != NULL) mTuneRequestCallback(); break;
okini3939 0:713ef38fead1 1004
okini3939 0:713ef38fead1 1005 case SystemReset: if (mSystemResetCallback != NULL) mSystemResetCallback(); break;
okini3939 0:713ef38fead1 1006 case InvalidType:
okini3939 0:713ef38fead1 1007 default:
okini3939 0:713ef38fead1 1008 break;
okini3939 0:713ef38fead1 1009 }
okini3939 0:713ef38fead1 1010
okini3939 0:713ef38fead1 1011 }
okini3939 0:713ef38fead1 1012
okini3939 0:713ef38fead1 1013
okini3939 0:713ef38fead1 1014 #endif // USE_CALLBACKS
okini3939 0:713ef38fead1 1015
okini3939 0:713ef38fead1 1016
okini3939 0:713ef38fead1 1017 #endif // COMPILE_MIDI_IN
okini3939 0:713ef38fead1 1018
okini3939 0:713ef38fead1 1019
okini3939 0:713ef38fead1 1020
okini3939 0:713ef38fead1 1021
okini3939 0:713ef38fead1 1022 #if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
okini3939 0:713ef38fead1 1023
okini3939 0:713ef38fead1 1024 /*! \brief Set the filter for thru mirroring
okini3939 0:713ef38fead1 1025 \param inThruFilterMode a filter mode
okini3939 0:713ef38fead1 1026
okini3939 0:713ef38fead1 1027 @see kThruFilterMode
okini3939 0:713ef38fead1 1028 */
okini3939 0:713ef38fead1 1029 void MIDI::setThruFilterMode(kThruFilterMode inThruFilterMode)
okini3939 0:713ef38fead1 1030 {
okini3939 0:713ef38fead1 1031
okini3939 0:713ef38fead1 1032 mThruFilterMode = inThruFilterMode;
okini3939 0:713ef38fead1 1033 if (mThruFilterMode != Off) mThruActivated = true;
okini3939 0:713ef38fead1 1034 else mThruActivated = false;
okini3939 0:713ef38fead1 1035
okini3939 0:713ef38fead1 1036 }
okini3939 0:713ef38fead1 1037
okini3939 0:713ef38fead1 1038
okini3939 0:713ef38fead1 1039 /*! \brief Setter method: turn message mirroring on. */
okini3939 0:713ef38fead1 1040 void MIDI::turnThruOn(kThruFilterMode inThruFilterMode)
okini3939 0:713ef38fead1 1041 {
okini3939 0:713ef38fead1 1042
okini3939 0:713ef38fead1 1043 mThruActivated = true;
okini3939 0:713ef38fead1 1044 mThruFilterMode = inThruFilterMode;
okini3939 0:713ef38fead1 1045
okini3939 0:713ef38fead1 1046 }
okini3939 0:713ef38fead1 1047
okini3939 0:713ef38fead1 1048
okini3939 0:713ef38fead1 1049 /*! \brief Setter method: turn message mirroring off. */
okini3939 0:713ef38fead1 1050 void MIDI::turnThruOff()
okini3939 0:713ef38fead1 1051 {
okini3939 0:713ef38fead1 1052
okini3939 0:713ef38fead1 1053 mThruActivated = false;
okini3939 0:713ef38fead1 1054 mThruFilterMode = Off;
okini3939 0:713ef38fead1 1055
okini3939 0:713ef38fead1 1056 }
okini3939 0:713ef38fead1 1057
okini3939 0:713ef38fead1 1058
okini3939 0:713ef38fead1 1059 // This method is called upon reception of a message and takes care of Thru filtering and sending.
okini3939 0:713ef38fead1 1060 void MIDI::thru_filter(byte inChannel)
okini3939 0:713ef38fead1 1061 {
okini3939 0:713ef38fead1 1062
okini3939 0:713ef38fead1 1063 /*
okini3939 0:713ef38fead1 1064 This method handles Soft-Thru filtering.
okini3939 0:713ef38fead1 1065
okini3939 0:713ef38fead1 1066 Soft-Thru filtering:
okini3939 0:713ef38fead1 1067 - All system messages (System Exclusive, Common and Real Time) are passed to output unless filter is set to Off
okini3939 0:713ef38fead1 1068 - Channel messages are passed to the output whether their channel is matching the input channel and the filter setting
okini3939 0:713ef38fead1 1069
okini3939 0:713ef38fead1 1070 */
okini3939 0:713ef38fead1 1071
okini3939 0:713ef38fead1 1072 // If the feature is disabled, don't do anything.
okini3939 0:713ef38fead1 1073 if (!mThruActivated || (mThruFilterMode == Off)) return;
okini3939 0:713ef38fead1 1074
okini3939 0:713ef38fead1 1075
okini3939 0:713ef38fead1 1076 // First, check if the received message is Channel
okini3939 0:713ef38fead1 1077 if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) {
okini3939 0:713ef38fead1 1078
okini3939 0:713ef38fead1 1079 const bool filter_condition = ((mMessage.channel == mInputChannel) || (mInputChannel == MIDI_CHANNEL_OMNI));
okini3939 0:713ef38fead1 1080
okini3939 0:713ef38fead1 1081 // Now let's pass it to the output
okini3939 0:713ef38fead1 1082 switch (mThruFilterMode) {
okini3939 0:713ef38fead1 1083 case Full:
okini3939 0:713ef38fead1 1084 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
okini3939 0:713ef38fead1 1085 return;
okini3939 0:713ef38fead1 1086 case SameChannel:
okini3939 0:713ef38fead1 1087 if (filter_condition) {
okini3939 0:713ef38fead1 1088 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
okini3939 0:713ef38fead1 1089 return;
okini3939 0:713ef38fead1 1090 }
okini3939 0:713ef38fead1 1091 break;
okini3939 0:713ef38fead1 1092 case DifferentChannel:
okini3939 0:713ef38fead1 1093 if (!filter_condition) {
okini3939 0:713ef38fead1 1094 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
okini3939 0:713ef38fead1 1095 return;
okini3939 0:713ef38fead1 1096 }
okini3939 0:713ef38fead1 1097 break;
okini3939 0:713ef38fead1 1098 case Off:
okini3939 0:713ef38fead1 1099 // Do nothing.
okini3939 0:713ef38fead1 1100 // Technically it's impossible to get there because the case was already tested earlier.
okini3939 0:713ef38fead1 1101 break;
okini3939 0:713ef38fead1 1102 default:
okini3939 0:713ef38fead1 1103 break;
okini3939 0:713ef38fead1 1104 }
okini3939 0:713ef38fead1 1105
okini3939 0:713ef38fead1 1106 }
okini3939 0:713ef38fead1 1107 else {
okini3939 0:713ef38fead1 1108
okini3939 0:713ef38fead1 1109 // Send the message to the output
okini3939 0:713ef38fead1 1110 switch (mMessage.type) {
okini3939 0:713ef38fead1 1111 // Real Time and 1 byte
okini3939 0:713ef38fead1 1112 case Clock:
okini3939 0:713ef38fead1 1113 case Start:
okini3939 0:713ef38fead1 1114 case Stop:
okini3939 0:713ef38fead1 1115 case Continue:
okini3939 0:713ef38fead1 1116 case ActiveSensing:
okini3939 0:713ef38fead1 1117 case SystemReset:
okini3939 0:713ef38fead1 1118 case TuneRequest:
okini3939 0:713ef38fead1 1119 sendRealTime(mMessage.type);
okini3939 0:713ef38fead1 1120 return;
okini3939 0:713ef38fead1 1121
okini3939 0:713ef38fead1 1122 case SystemExclusive:
okini3939 0:713ef38fead1 1123 // Send SysEx (0xF0 and 0xF7 are included in the buffer)
okini3939 0:713ef38fead1 1124 sendSysEx(mMessage.data1,mMessage.sysex_array,true);
okini3939 0:713ef38fead1 1125 return;
okini3939 0:713ef38fead1 1126
okini3939 0:713ef38fead1 1127 case SongSelect:
okini3939 0:713ef38fead1 1128 sendSongSelect(mMessage.data1);
okini3939 0:713ef38fead1 1129 return;
okini3939 0:713ef38fead1 1130
okini3939 0:713ef38fead1 1131 case SongPosition:
okini3939 0:713ef38fead1 1132 sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2<<7));
okini3939 0:713ef38fead1 1133 return;
okini3939 0:713ef38fead1 1134
okini3939 0:713ef38fead1 1135 case TimeCodeQuarterFrame:
okini3939 0:713ef38fead1 1136 sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);
okini3939 0:713ef38fead1 1137 return;
okini3939 0:713ef38fead1 1138
okini3939 0:713ef38fead1 1139 default:
okini3939 0:713ef38fead1 1140 break;
okini3939 0:713ef38fead1 1141
okini3939 0:713ef38fead1 1142 }
okini3939 0:713ef38fead1 1143
okini3939 0:713ef38fead1 1144 }
okini3939 0:713ef38fead1 1145
okini3939 0:713ef38fead1 1146 }
okini3939 0:713ef38fead1 1147
okini3939 0:713ef38fead1 1148
okini3939 0:713ef38fead1 1149 #endif // Thru