X-TOUCH to djay bridge

Dependencies:   mbed mbed-rtos FATFileSystem

Committer:
okini3939
Date:
Wed Jun 05 04:54:37 2019 +0000
Revision:
1:0dac72ab5910
sample

Who changed what in which revision?

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