X-TOUCH to djay bridge

Dependencies:   mbed mbed-rtos FATFileSystem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MIDI.cpp Source File

MIDI.cpp

Go to the documentation of this file.
00001 /*!
00002  *  @file       MIDI.cpp
00003  *  Project     MIDI Library
00004  *  @brief      MIDI Library for the Arduino
00005  *  @version    3.2
00006  *  @author     Francois Best 
00007  *  @date       24/02/11
00008  *  license     GPL Forty Seven Effects - 2011
00009  */
00010 /*
00011  * Ported for mbed by Hiroshi Suga
00012  *   Orignal: http://www.arduino.cc/playground/Main/MIDILibrary
00013  */
00014 
00015 #include "MIDI.h"
00016 #include "mbed.h"
00017 
00018 
00019 
00020 /*! \brief Default constructor for MIDI. */
00021 MIDI::MIDI(PinName p_tx, PinName p_rx) : _midi(p_tx, p_rx)
00022 { 
00023     uart_in = new CircBuffer <byte>(80);
00024 
00025 #if USE_CALLBACKS
00026     
00027     // Initialise callbacks to NULL pointer
00028     mNoteOffCallback                = NULL;
00029     mNoteOnCallback                 = NULL;
00030     mAfterTouchPolyCallback         = NULL;
00031     mControlChangeCallback          = NULL;
00032     mProgramChangeCallback          = NULL;
00033     mAfterTouchChannelCallback      = NULL;
00034     mPitchBendCallback              = NULL;
00035     mSystemExclusiveCallback        = NULL;
00036     mTimeCodeQuarterFrameCallback   = NULL;
00037     mSongPositionCallback           = NULL;
00038     mSongSelectCallback             = NULL;
00039     mTuneRequestCallback            = NULL;
00040     mClockCallback                  = NULL;
00041     mStartCallback                  = NULL;
00042     mContinueCallback               = NULL;
00043     mStopCallback                   = NULL;
00044     mActiveSensingCallback          = NULL;
00045     mSystemResetCallback            = NULL;
00046     
00047 #endif
00048     
00049 }
00050 
00051 
00052 /*! \brief Default destructor for MIDI.
00053  
00054  This is not really useful for the Arduino, as it is never called...
00055  */
00056 MIDI::~MIDI()
00057 {
00058 
00059 }
00060 
00061 
00062 void MIDI::isr_rx () {
00063     uart_in->queue(USE_SERIAL_PORT.getc());
00064 }
00065 
00066 /*! \brief Call the begin method in the setup() function of the Arduino.
00067  
00068  All parameters are set to their default values:
00069  - Input channel set to 1 if no value is specified
00070  - Full thru mirroring
00071  */
00072 void MIDI::begin(const byte  inChannel)
00073 {
00074     
00075     // Initialise the Serial port
00076     USE_SERIAL_PORT.baud(MIDI_BAUDRATE);
00077     USE_SERIAL_PORT.attach(this, &MIDI::isr_rx, Serial::RxIrq);
00078     
00079     
00080 #if COMPILE_MIDI_OUT
00081     
00082 #if USE_RUNNING_STATUS
00083     
00084     mRunningStatus_TX = InvalidType;
00085     
00086 #endif // USE_RUNNING_STATUS
00087     
00088 #endif // COMPILE_MIDI_OUT
00089     
00090     
00091 #if COMPILE_MIDI_IN
00092     
00093     mInputChannel = inChannel;
00094     mRunningStatus_RX = InvalidType;
00095     mPendingMessageIndex = 0;
00096     mPendingMessageExpectedLenght = 0;
00097     
00098     mMessage.valid  = false;
00099     mMessage.type  = InvalidType;
00100     mMessage.channel  = 0;
00101     mMessage.data1  = 0;
00102     mMessage.data2  = 0;
00103     
00104 #endif // COMPILE_MIDI_IN
00105     
00106     
00107 #if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
00108     
00109     mThruFilterMode = Full;
00110     mThruActivated = true;
00111     
00112 #endif // Thru
00113     
00114 }
00115 
00116 
00117 #if COMPILE_MIDI_OUT
00118 
00119 // Private method for generating a status byte from channel and type
00120 byte  MIDI::genstatus(const kMIDIType  inType,
00121                                  const byte  inChannel) const
00122 {
00123     
00124     return ((byte )inType | ((inChannel-1) & 0x0F));
00125     
00126 }
00127 
00128 
00129 /*! \brief Generate and send a MIDI message from the values given.
00130  \param type    The message type (see type defines for reference)
00131  \param data1   The first data byte.
00132  \param data2   The second data byte (if the message contains only 1 data byte, set this one to 0).
00133  \param channel The output channel on which the message will be sent (values from 1 to 16). Note: you cannot send to OMNI.
00134  
00135  This is an internal method, use it only if you need to send raw data from your code, at your own risks.
00136  */
00137 void MIDI::send(kMIDIType  type,
00138                       byte  data1,
00139                       byte  data2,
00140                       byte  channel)
00141 {
00142     
00143     // Then test if channel is valid
00144 //    if (channel >= MIDI_CHANNEL_OFF || channel == MIDI_CHANNEL_OMNI || type < NoteOff) {
00145     if (channel >= MIDI_CHANNEL_OFF || channel < MIDI_CHANNEL_OMNI || type < NoteOff) {
00146         
00147 #if USE_RUNNING_STATUS  
00148         mRunningStatus_TX = InvalidType;
00149 #endif 
00150         
00151         return; // Don't send anything
00152     }
00153     
00154     if (type <= PitchBend) {
00155         // Channel messages
00156         
00157         // Protection: remove MSBs on data
00158         data1 &= 0x7F;
00159         data2 &= 0x7F;
00160         
00161         byte  statusbyte = genstatus(type,channel);
00162         
00163 #if USE_RUNNING_STATUS
00164         // Check Running Status
00165         if (mRunningStatus_TX != statusbyte) {
00166             // New message, memorise and send header
00167             mRunningStatus_TX = statusbyte;
00168             USE_SERIAL_PORT.putc(mRunningStatus_TX);
00169         }
00170 #else
00171         // Don't care about running status, send the Control byte.
00172         USE_SERIAL_PORT.putc(statusbyte);
00173 #endif
00174         
00175         // Then send data
00176         USE_SERIAL_PORT.putc(data1);
00177         if (type != ProgramChange && type != AfterTouchChannel) {
00178             USE_SERIAL_PORT.putc(data2);
00179         }
00180         return;
00181     }
00182     if (type >= TuneRequest && type <= SystemReset) {
00183         // System Real-time and 1 byte.
00184         sendRealTime(type);
00185     }
00186     
00187 }
00188 
00189 
00190 /*! \brief Send a Note On message 
00191  \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
00192  \param Velocity    Note attack velocity (0 to 127). A NoteOn with 0 velocity is considered as a NoteOff.
00193  \param Channel     The channel on which the message will be sent (1 to 16). 
00194  */
00195 void MIDI::sendNoteOn(byte  NoteNumber,
00196                             byte  Velocity,
00197                             byte  Channel)
00198 { 
00199     
00200     send(NoteOn,NoteNumber,Velocity,Channel);
00201 
00202 }
00203 
00204 
00205 /*! \brief Send a Note Off message (a real Note Off, not a Note On with null velocity)
00206  \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
00207  \param Velocity    Release velocity (0 to 127).
00208  \param Channel     The channel on which the message will be sent (1 to 16).
00209  */
00210 void MIDI::sendNoteOff(byte  NoteNumber,
00211                              byte  Velocity,
00212                              byte  Channel)
00213 {
00214     
00215     send(NoteOff,NoteNumber,Velocity,Channel);
00216 
00217 }
00218 
00219 
00220 /*! \brief Send a Program Change message 
00221  \param ProgramNumber   The Program to select (0 to 127).
00222  \param Channel         The channel on which the message will be sent (1 to 16).
00223  */
00224 void MIDI::sendProgramChange(byte  ProgramNumber,
00225                                    byte  Channel)
00226 {
00227     
00228     send(ProgramChange,ProgramNumber,0,Channel);
00229 
00230 }
00231 
00232 
00233 /*! \brief Send a Control Change message 
00234  \param ControlNumber   The controller number (0 to 127). See the detailed description here: http://www.somascape.org/midi/tech/spec.html#ctrlnums
00235  \param ControlValue    The value for the specified controller (0 to 127).
00236  \param Channel         The channel on which the message will be sent (1 to 16). 
00237  */
00238 void MIDI::sendControlChange(byte  ControlNumber,
00239                                    byte  ControlValue,
00240                                    byte  Channel)
00241 {
00242     
00243     send(ControlChange,ControlNumber,ControlValue,Channel);
00244 
00245 }
00246 
00247 
00248 /*! \brief Send a Polyphonic AfterTouch message (applies to only one specified note)
00249  \param NoteNumber      The note to apply AfterTouch to (0 to 127).
00250  \param Pressure        The amount of AfterTouch to apply (0 to 127).
00251  \param Channel         The channel on which the message will be sent (1 to 16). 
00252  */
00253 void MIDI::sendPolyPressure(byte  NoteNumber,
00254                                   byte  Pressure,
00255                                   byte  Channel)
00256 {
00257     
00258     send(AfterTouchPoly,NoteNumber,Pressure,Channel);
00259 
00260 }
00261 
00262 
00263 /*! \brief Send a MonoPhonic AfterTouch message (applies to all notes)
00264  \param Pressure        The amount of AfterTouch to apply to all notes.
00265  \param Channel         The channel on which the message will be sent (1 to 16). 
00266  */
00267 void MIDI::sendAfterTouch(byte  Pressure,
00268                                 byte  Channel)
00269 {
00270     
00271     send(AfterTouchChannel,Pressure,0,Channel);
00272 
00273 }
00274 
00275 
00276 /*! \brief Send a Pitch Bend message using a signed integer value.
00277  \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.
00278  \param Channel     The channel on which the message will be sent (1 to 16).
00279  */
00280 void MIDI::sendPitchBend(int PitchValue,
00281                                byte  Channel)
00282 {
00283     
00284     unsigned int bend = PitchValue + 8192;
00285     sendPitchBend(bend,Channel);
00286     
00287 }
00288 
00289 
00290 /*! \brief Send a Pitch Bend message using an unsigned integer value.
00291  \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.
00292  \param Channel     The channel on which the message will be sent (1 to 16).
00293  */
00294 void MIDI::sendPitchBend(unsigned int PitchValue,
00295                                byte  Channel)
00296 {
00297     
00298     send(PitchBend,(PitchValue & 0x7F),(PitchValue >> 7) & 0x7F,Channel);
00299     
00300 }
00301 
00302 
00303 /*! \brief Send a Pitch Bend message using a floating point value.
00304  \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.
00305  \param Channel     The channel on which the message will be sent (1 to 16).
00306  */
00307 void MIDI::sendPitchBend(double PitchValue,
00308                                byte  Channel)
00309 {
00310     
00311     unsigned int pitchval = (PitchValue+1.f)*8192;
00312     if (pitchval > 16383) pitchval = 16383;     // overflow protection
00313     sendPitchBend(pitchval,Channel);
00314     
00315 }
00316 
00317 
00318 /*! \brief Generate and send a System Exclusive frame.
00319  \param length  The size of the array to send
00320  \param array   The byte array containing the data to send
00321  \param ArrayContainsBoundaries  When set to 'true', 0xF0 & 0xF7 bytes (start & stop SysEx) will NOT be sent (and therefore must be included in the array).
00322  default value is set to 'false' for compatibility with previous versions of the library.
00323  */
00324 void MIDI::sendSysEx(int length,
00325                            const byte  *const array,
00326                            bool ArrayContainsBoundaries)
00327 {
00328     
00329     if (ArrayContainsBoundaries == false) {
00330         
00331         USE_SERIAL_PORT.putc(0xF0);
00332         
00333         for (int i=0;i<length;++i) {
00334             
00335             USE_SERIAL_PORT.putc(array[i]);
00336             
00337         }
00338         
00339         USE_SERIAL_PORT.putc(0xF7);
00340         
00341     }
00342     else {
00343         
00344         for (int i=0;i<length;++i) {
00345             
00346             USE_SERIAL_PORT.putc(array[i]);
00347             
00348         }
00349         
00350     }
00351     
00352 #if USE_RUNNING_STATUS
00353     mRunningStatus_TX = InvalidType;
00354 #endif
00355     
00356 }
00357 
00358 
00359 /*! \brief Send a Tune Request message. 
00360  
00361  When a MIDI unit receives this message, it should tune its oscillators (if equipped with any) 
00362  */
00363 void MIDI::sendTuneRequest()
00364 {
00365     
00366     sendRealTime(TuneRequest);
00367 
00368 }
00369 
00370 
00371 /*! \brief Send a MIDI Time Code Quarter Frame. 
00372  
00373  See MIDI Specification for more information.
00374  \param TypeNibble  MTC type
00375  \param ValuesNibble    MTC data
00376  */
00377 void MIDI::sendTimeCodeQuarterFrame(byte  TypeNibble, byte  ValuesNibble)
00378 {
00379     
00380     byte  data = ( ((TypeNibble & 0x07) << 4) | (ValuesNibble & 0x0F) );
00381     sendTimeCodeQuarterFrame(data);
00382     
00383 }
00384 
00385 
00386 /*! \brief Send a MIDI Time Code Quarter Frame. 
00387  
00388  See MIDI Specification for more information.
00389  \param data     if you want to encode directly the nibbles in your program, you can send the byte here.
00390  */
00391 void MIDI::sendTimeCodeQuarterFrame(byte  data)
00392 {
00393     
00394     USE_SERIAL_PORT.putc((byte )TimeCodeQuarterFrame);
00395     USE_SERIAL_PORT.putc(data);
00396 
00397 #if USE_RUNNING_STATUS
00398     mRunningStatus_TX = InvalidType;
00399 #endif
00400     
00401 }
00402 
00403 
00404 /*! \brief Send a Song Position Pointer message.
00405  \param Beats   The number of beats since the start of the song.
00406  */
00407 void MIDI::sendSongPosition(unsigned int Beats)
00408 {
00409     
00410     USE_SERIAL_PORT.putc((byte )SongPosition);
00411     USE_SERIAL_PORT.putc(Beats & 0x7F);
00412     USE_SERIAL_PORT.putc((Beats >> 7) & 0x7F);
00413 
00414 #if USE_RUNNING_STATUS
00415     mRunningStatus_TX = InvalidType;
00416 #endif
00417     
00418 }
00419 
00420 
00421 /*! \brief Send a Song Select message */
00422 void MIDI::sendSongSelect(byte  SongNumber)
00423 {
00424     
00425     USE_SERIAL_PORT.putc((byte )SongSelect);
00426     USE_SERIAL_PORT.putc(SongNumber & 0x7F);
00427 
00428 #if USE_RUNNING_STATUS
00429     mRunningStatus_TX = InvalidType;
00430 #endif
00431     
00432 }
00433 
00434 
00435 /*! \brief Send a Real Time (one byte) message. 
00436  
00437  \param Type The available Real Time types are: Start, Stop, Continue, Clock, ActiveSensing and SystemReset.
00438  You can also send a Tune Request with this method.
00439  @see kMIDIType
00440  */
00441 void MIDI::sendRealTime(kMIDIType  Type)
00442 {
00443     switch (Type) {
00444         case TuneRequest: // Not really real-time, but one byte anyway.
00445         case Clock:
00446         case Start:
00447         case Stop:  
00448         case Continue:
00449         case ActiveSensing:
00450         case SystemReset:
00451             USE_SERIAL_PORT.putc((byte )Type);
00452             break;
00453         default:
00454             // Invalid Real Time marker
00455             break;
00456     }
00457     
00458     // Do not cancel Running Status for real-time messages as they can be interleaved within any message.
00459     // Though, TuneRequest can be sent here, and as it is a System Common message, it must reset Running Status.
00460 #if USE_RUNNING_STATUS
00461     if (Type == TuneRequest) mRunningStatus_TX = InvalidType;
00462 #endif
00463     
00464 }
00465 
00466 #endif // COMPILE_MIDI_OUT
00467 
00468 
00469 
00470 #if COMPILE_MIDI_IN
00471 
00472 /*! \brief Read a MIDI message from the serial port using the main input channel (see setInputChannel() for reference).
00473  
00474  Returned value: true if any valid message has been stored in the structure, false if not.
00475  A valid message is a message that matches the input channel. \n\n
00476  If the Thru is enabled and the messages matches the filter, it is sent back on the MIDI output.
00477  */
00478 bool MIDI::read()
00479 {
00480     
00481     return read(mInputChannel);
00482     
00483 }
00484 
00485 
00486 /*! \brief Reading/thru-ing method, the same as read() with a given input channel to read on. */
00487 bool MIDI::read(const byte  inChannel)
00488 {
00489     
00490     if (inChannel >= MIDI_CHANNEL_OFF) return false; // MIDI Input disabled.
00491     
00492     if (parse(inChannel)) {
00493         
00494         if (input_filter(inChannel)) {
00495             
00496 #if (COMPILE_MIDI_OUT && COMPILE_MIDI_THRU)
00497             thru_filter(inChannel);
00498 #endif
00499             
00500 #if USE_CALLBACKS
00501             launchCallback();
00502 #endif
00503             
00504             return true;
00505         }
00506         
00507     }
00508     
00509     return false;
00510     
00511 }
00512 
00513 
00514 // Private method: MIDI parser
00515 bool MIDI::parse(byte  inChannel)
00516 { 
00517     
00518 //    const int bytes_available = USE_SERIAL_PORT.readable();
00519     const int bytes_available = !uart_in->isEmpty();
00520     
00521     if (bytes_available <= 0) {
00522         // No data available.
00523         return false;
00524     }
00525     
00526     // If the buffer is full -> Don't Panic! Call the Vogons to destroy it.
00527     if (bytes_available == 128) {
00528 //        USE_SERIAL_PORT.flush();
00529     }   
00530     else {
00531         
00532         /* Parsing algorithm:
00533          Get a byte from the serial buffer.
00534          * If there is no pending message to be recomposed, start a new one.
00535          - Find type and channel (if pertinent)
00536          - Look for other bytes in buffer, call parser recursively, until the message is assembled or the buffer is empty.
00537          * Else, add the extracted byte to the pending message, and check validity. When the message is done, store it.
00538          */
00539         
00540         
00541 //        const byte extracted = USE_SERIAL_PORT.getc();
00542         byte  extracted;
00543         uart_in->dequeue(&extracted);
00544         
00545         if (mPendingMessageIndex == 0) { // Start a new pending message
00546             mPendingMessage[0] = extracted;
00547             
00548             // Check for running status first
00549             switch (getTypeFromStatusByte(mRunningStatus_RX)) {
00550                     // Only these types allow Running Status:
00551                 case NoteOff:
00552                 case NoteOn:
00553                 case AfterTouchPoly:
00554                 case ControlChange:
00555                 case ProgramChange:
00556                 case AfterTouchChannel:
00557                 case PitchBend: 
00558                     
00559                     // If the status byte is not received, prepend it to the pending message
00560                     if (extracted < 0x80) {
00561                         mPendingMessage[0] = mRunningStatus_RX;
00562                         mPendingMessage[1] = extracted;
00563                         mPendingMessageIndex = 1;
00564                     }
00565                     // Else: well, we received another status byte, so the running status does not apply here.
00566                     // It will be updated upon completion of this message.
00567                     
00568                     break;
00569                     
00570                 default:
00571                     // No running status
00572                     break;
00573             }
00574             
00575             
00576             switch (getTypeFromStatusByte(mPendingMessage[0])) {
00577                     
00578                     // 1 byte messages
00579                 case Start:
00580                 case Continue:
00581                 case Stop:
00582                 case Clock:
00583                 case ActiveSensing:
00584                 case SystemReset:
00585                 case TuneRequest:
00586                     // Handle the message type directly here.
00587                     mMessage.type  = getTypeFromStatusByte(mPendingMessage[0]);
00588                     mMessage.channel  = 0;
00589                     mMessage.data1  = 0;
00590                     mMessage.data2  = 0;
00591                     mMessage.valid  = true;
00592                     
00593                     // \fix Running Status broken when receiving Clock messages.
00594                     // Do not reset all input attributes, Running Status must remain unchanged.
00595                     //reset_input_attributes(); 
00596                     
00597                     // We still need to reset these
00598                     mPendingMessageIndex = 0;
00599                     mPendingMessageExpectedLenght = 0;
00600                     
00601                     return true;
00602                     
00603                     // 2 bytes messages
00604                 case ProgramChange:
00605                 case AfterTouchChannel:
00606                 case TimeCodeQuarterFrame:
00607                 case SongSelect:
00608                     mPendingMessageExpectedLenght = 2;
00609                     break;
00610                     
00611                     // 3 bytes messages
00612                 case NoteOn:
00613                 case NoteOff:
00614                 case ControlChange:
00615                 case PitchBend:
00616                 case AfterTouchPoly:
00617                 case SongPosition:
00618                     mPendingMessageExpectedLenght = 3;
00619                     break;
00620                     
00621                 case SystemExclusive:
00622                     mPendingMessageExpectedLenght = MIDI_SYSEX_ARRAY_SIZE; // As the message can be any lenght between 3 and MIDI_SYSEX_ARRAY_SIZE bytes
00623                     mRunningStatus_RX = InvalidType;
00624                     break;
00625                     
00626                 case InvalidType:
00627                 default:
00628                     // This is obviously wrong. Let's get the hell out'a here.
00629                     reset_input_attributes();
00630                     return false;
00631             }
00632             
00633             // Then update the index of the pending message.
00634             mPendingMessageIndex++;
00635             
00636 #if USE_1BYTE_PARSING
00637             // Message is not complete.
00638             return false;
00639 #else
00640             // Call the parser recursively
00641             // to parse the rest of the message.
00642             return parse(inChannel);
00643 #endif
00644             
00645         }
00646         else { 
00647             
00648             // First, test if this is a status byte
00649             if (extracted >= 0x80) {
00650                 
00651                 // Reception of status bytes in the middle of an uncompleted message
00652                 // are allowed only for interleaved Real Time message or EOX
00653                 switch (extracted) {
00654                     case Clock:
00655                     case Start:
00656                     case Continue:
00657                     case Stop:
00658                     case ActiveSensing:
00659                     case SystemReset:
00660                         
00661                         /*
00662                          This is tricky. Here we will have to extract the one-byte message,
00663                          pass it to the structure for being read outside the MIDI class,
00664                          and recompose the message it was interleaved into.
00665                          
00666                          Oh, and without killing the running status.. 
00667                          
00668                          This is done by leaving the pending message as is, it will be completed on next calls.
00669                          */
00670                         
00671                         mMessage.type  = (kMIDIType )extracted;
00672                         mMessage.data1  = 0;
00673                         mMessage.data2  = 0;
00674                         mMessage.channel  = 0;
00675                         mMessage.valid  = true;
00676                         return true;
00677                         
00678                         // End of Exclusive
00679                     case 0xF7:
00680                         if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
00681                             
00682                             // Store System Exclusive array in midimsg structure
00683                             for (byte  i=0;i<MIDI_SYSEX_ARRAY_SIZE;i++) {
00684                                 mMessage.sysex_array [i] = mPendingMessage[i];
00685                             }
00686                             
00687                             mMessage.type  = SystemExclusive;
00688 
00689                             // Get length
00690                             mMessage.data1  = (mPendingMessageIndex+1) & 0xFF;   
00691                             mMessage.data2  = (mPendingMessageIndex+1) >> 8;
00692                             
00693                             mMessage.channel  = 0;
00694                             mMessage.valid  = true;
00695                             
00696                             reset_input_attributes();
00697                             
00698                             return true;
00699                         }
00700                         else {
00701                             // Well well well.. error.
00702                             reset_input_attributes();
00703                             return false;
00704                         }
00705                         
00706                     default:
00707                         break;
00708                 }
00709                 
00710                 
00711                 
00712             }
00713             
00714             
00715             // Add extracted data byte to pending message
00716             mPendingMessage[mPendingMessageIndex] = extracted;
00717             
00718             
00719             // Now we are going to check if we have reached the end of the message
00720             if (mPendingMessageIndex >= (mPendingMessageExpectedLenght-1)) {
00721                 
00722                 // "FML" case: fall down here with an overflown SysEx..
00723                 // This means we received the last possible data byte that can fit the buffer.
00724                 // If this happens, try increasing MIDI_SYSEX_ARRAY_SIZE.
00725                 if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
00726                     reset_input_attributes();
00727                     return false;
00728                 }
00729                 
00730                 
00731                 mMessage.type  = getTypeFromStatusByte(mPendingMessage[0]);
00732                 mMessage.channel  = (mPendingMessage[0] & 0x0F)+1; // Don't check if it is a Channel Message
00733                 
00734                 mMessage.data1  = mPendingMessage[1];
00735                 
00736                 // Save data2 only if applicable
00737                 if (mPendingMessageExpectedLenght == 3) mMessage.data2  = mPendingMessage[2];
00738                 else mMessage.data2  = 0;
00739                 
00740                 // Reset local variables
00741                 mPendingMessageIndex = 0;
00742                 mPendingMessageExpectedLenght = 0;
00743                 
00744                 mMessage.valid  = true;
00745                 
00746                 // Activate running status (if enabled for the received type)
00747                 switch (mMessage.type ) {
00748                     case NoteOff:
00749                     case NoteOn:
00750                     case AfterTouchPoly:
00751                     case ControlChange:
00752                     case ProgramChange:
00753                     case AfterTouchChannel:
00754                     case PitchBend: 
00755                         // Running status enabled: store it from received message
00756                         mRunningStatus_RX = mPendingMessage[0];
00757                         break;
00758                         
00759                     default:
00760                         // No running status
00761                         mRunningStatus_RX = InvalidType;
00762                         break;
00763                 }
00764                 return true;
00765             }
00766             else {
00767                 // Then update the index of the pending message.
00768                 mPendingMessageIndex++;
00769                 
00770 #if USE_1BYTE_PARSING
00771                 // Message is not complete.
00772                 return false;
00773 #else
00774                 // Call the parser recursively
00775                 // to parse the rest of the message.
00776                 return parse(inChannel);
00777 #endif
00778                 
00779             }
00780             
00781         }
00782         
00783     }
00784     
00785     // What are our chances to fall here?
00786     return false;
00787 }
00788 
00789 
00790 // Private method: check if the received message is on the listened channel
00791 bool MIDI::input_filter(byte  inChannel)
00792 {
00793     
00794     
00795     // This method handles recognition of channel (to know if the message is destinated to the Arduino)
00796     
00797     
00798     if (mMessage.type  == InvalidType) return false;
00799     
00800     
00801     // First, check if the received message is Channel
00802     if (mMessage.type  >= NoteOff && mMessage.type  <= PitchBend) {
00803         
00804         // Then we need to know if we listen to it
00805         if ((mMessage.channel  == mInputChannel) || (mInputChannel == MIDI_CHANNEL_OMNI)) {
00806             return true;
00807             
00808         }
00809         else {
00810             // We don't listen to this channel
00811             return false;
00812         }
00813         
00814     }
00815     else {
00816         
00817         // System messages are always received
00818         return true;
00819     }
00820     
00821 }
00822 
00823 
00824 // Private method: reset input attributes
00825 void MIDI::reset_input_attributes()
00826 {
00827     
00828     mPendingMessageIndex = 0;
00829     mPendingMessageExpectedLenght = 0;
00830     mRunningStatus_RX = InvalidType;
00831     
00832 }
00833 
00834 
00835 // Getters
00836 /*! \brief Get the last received message's type
00837  
00838  Returns an enumerated type. @see kMIDIType
00839  */
00840 kMIDIType  MIDI::getType() const
00841 {
00842     
00843     return mMessage.type ;
00844 
00845 }
00846 
00847 
00848 /*! \brief Get the channel of the message stored in the structure.
00849  
00850  Channel range is 1 to 16. For non-channel messages, this will return 0.
00851  */
00852 byte  MIDI::getChannel() const
00853 {
00854     
00855     return mMessage.channel ;
00856 
00857 }
00858 
00859 
00860 /*! \brief Get the first data byte of the last received message. */
00861 byte  MIDI::getData1() const
00862 {
00863     
00864     return mMessage.data1 ;
00865 
00866 }
00867 
00868 
00869 /*! \brief Get the second data byte of the last received message. */
00870 byte  MIDI::getData2() const
00871 { 
00872     
00873     return mMessage.data2 ;
00874 
00875 }
00876 
00877 
00878 /*! \brief Get the System Exclusive byte array. 
00879  
00880  @see getSysExArrayLength to get the array's length in bytes.
00881  */
00882 const byte  * MIDI::getSysExArray() const
00883 { 
00884     
00885     return mMessage.sysex_array ;
00886 
00887 }
00888 
00889 /*! \brief Get the lenght of the System Exclusive array.
00890  
00891  It is coded using data1 as LSB and data2 as MSB.
00892  \return The array's length, in bytes.
00893  */
00894 unsigned int MIDI::getSysExArrayLength() const
00895 {
00896     
00897     unsigned int coded_size = ((unsigned int)(mMessage.data2 ) << 8) | mMessage.data1 ;
00898     
00899     return (coded_size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : coded_size;
00900     
00901 }
00902 
00903 
00904 /*! \brief Check if a valid message is stored in the structure. */
00905 bool MIDI::check() const
00906 { 
00907     
00908     return mMessage.valid ;
00909 
00910 }
00911 
00912 
00913 // Setters
00914 /*! \brief Set the value for the input MIDI channel 
00915  \param Channel the channel value. Valid values are 1 to 16, 
00916  MIDI_CHANNEL_OMNI if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable MIDI input.
00917  */
00918 void MIDI::setInputChannel(const byte  Channel)
00919 { 
00920     
00921     mInputChannel = Channel;
00922     
00923 }
00924 
00925 
00926 #if USE_CALLBACKS
00927 
00928 void MIDI::setHandleNoteOff(void (*fptr)(byte  channel, byte  note, byte  velocity))         { mNoteOffCallback = fptr; }
00929 void MIDI::setHandleNoteOn(void (*fptr)(byte  channel, byte  note, byte  velocity))          { mNoteOnCallback = fptr; }
00930 void MIDI::setHandleAfterTouchPoly(void (*fptr)(byte  channel, byte  note, byte  pressure))  { mAfterTouchPolyCallback = fptr; }
00931 void MIDI::setHandleControlChange(void (*fptr)(byte  channel, byte  number, byte  value))    { mControlChangeCallback = fptr; }
00932 void MIDI::setHandleProgramChange(void (*fptr)(byte  channel, byte  number))                { mProgramChangeCallback = fptr; }
00933 void MIDI::setHandleAfterTouchChannel(void (*fptr)(byte  channel, byte  pressure))          { mAfterTouchChannelCallback = fptr; }
00934 void MIDI::setHandlePitchBend(void (*fptr)(byte  channel, int bend))                       { mPitchBendCallback = fptr; }
00935 void MIDI::setHandleSystemExclusive(void (*fptr)(byte  * array, byte  size))                { mSystemExclusiveCallback = fptr; }
00936 void MIDI::setHandleTimeCodeQuarterFrame(void (*fptr)(byte  data))                         { mTimeCodeQuarterFrameCallback = fptr; }
00937 void MIDI::setHandleSongPosition(void (*fptr)(unsigned int beats))                        { mSongPositionCallback = fptr; }
00938 void MIDI::setHandleSongSelect(void (*fptr)(byte  songnumber))                             { mSongSelectCallback = fptr; }
00939 void MIDI::setHandleTuneRequest(void (*fptr)(void))                                       { mTuneRequestCallback = fptr; }
00940 void MIDI::setHandleClock(void (*fptr)(void))                                             { mClockCallback = fptr; }
00941 void MIDI::setHandleStart(void (*fptr)(void))                                             { mStartCallback = fptr; }
00942 void MIDI::setHandleContinue(void (*fptr)(void))                                          { mContinueCallback = fptr; }
00943 void MIDI::setHandleStop(void (*fptr)(void))                                              { mStopCallback = fptr; }
00944 void MIDI::setHandleActiveSensing(void (*fptr)(void))                                     { mActiveSensingCallback = fptr; }
00945 void MIDI::setHandleSystemReset(void (*fptr)(void))                                       { mSystemResetCallback = fptr; }
00946 
00947 
00948 /*! \brief Detach an external function from the given type.
00949  
00950  Use this method to cancel the effects of setHandle********.
00951  \param Type        The type of message to unbind. When a message of this type is received, no function will be called.
00952  */
00953 void MIDI::disconnectCallbackFromType(kMIDIType  Type)
00954 {
00955     
00956     switch (Type) {
00957         case NoteOff:               mNoteOffCallback = NULL;                break;
00958         case NoteOn:                mNoteOnCallback = NULL;                 break;
00959         case AfterTouchPoly:        mAfterTouchPolyCallback = NULL;         break;
00960         case ControlChange:         mControlChangeCallback = NULL;          break;
00961         case ProgramChange:         mProgramChangeCallback = NULL;          break;
00962         case AfterTouchChannel:     mAfterTouchChannelCallback = NULL;      break;
00963         case PitchBend:             mPitchBendCallback = NULL;              break;
00964         case SystemExclusive:       mSystemExclusiveCallback = NULL;        break;
00965         case TimeCodeQuarterFrame:  mTimeCodeQuarterFrameCallback = NULL;   break;
00966         case SongPosition:          mSongPositionCallback = NULL;           break;
00967         case SongSelect:            mSongSelectCallback = NULL;             break;
00968         case TuneRequest:           mTuneRequestCallback = NULL;            break;
00969         case Clock:                 mClockCallback = NULL;                  break;
00970         case Start:                 mStartCallback = NULL;                  break;
00971         case Continue:              mContinueCallback = NULL;               break;
00972         case Stop:                  mStopCallback = NULL;                   break;
00973         case ActiveSensing:         mActiveSensingCallback = NULL;          break;
00974         case SystemReset:           mSystemResetCallback = NULL;            break;
00975         default:
00976             break;
00977     }
00978     
00979 }
00980 
00981 
00982 // Private - launch callback function based on received type.
00983 void MIDI::launchCallback()
00984 {
00985     
00986     // The order is mixed to allow frequent messages to trigger their callback faster.
00987     
00988     switch (mMessage.type ) {
00989             // Notes
00990         case NoteOff:               if (mNoteOffCallback != NULL)               mNoteOffCallback(mMessage.channel ,mMessage.data1 ,mMessage.data2 );   break;
00991         case NoteOn:                if (mNoteOnCallback != NULL)                mNoteOnCallback(mMessage.channel ,mMessage.data1 ,mMessage.data2 );    break;
00992             
00993             // Real-time messages
00994         case Clock:                 if (mClockCallback != NULL)                 mClockCallback();           break;          
00995         case Start:                 if (mStartCallback != NULL)                 mStartCallback();           break;
00996         case Continue:              if (mContinueCallback != NULL)              mContinueCallback();        break;
00997         case Stop:                  if (mStopCallback != NULL)                  mStopCallback();            break;
00998         case ActiveSensing:         if (mActiveSensingCallback != NULL)         mActiveSensingCallback();   break;
00999             
01000             // Continuous controllers
01001         case ControlChange:         if (mControlChangeCallback != NULL)         mControlChangeCallback(mMessage.channel ,mMessage.data1 ,mMessage.data2 ); break;
01002         case PitchBend:             if (mPitchBendCallback != NULL)             mPitchBendCallback(mMessage.channel ,(int)((mMessage.data1  & 0x7F) | ((mMessage.data2  & 0x7F)<< 7)) - 8192); break; // TODO: check this
01003         case AfterTouchPoly:        if (mAfterTouchPolyCallback != NULL)        mAfterTouchPolyCallback(mMessage.channel ,mMessage.data1 ,mMessage.data2 );    break;
01004         case AfterTouchChannel:     if (mAfterTouchChannelCallback != NULL)     mAfterTouchChannelCallback(mMessage.channel ,mMessage.data1 );    break;
01005             
01006         case ProgramChange:         if (mProgramChangeCallback != NULL)         mProgramChangeCallback(mMessage.channel ,mMessage.data1 );    break;
01007         case SystemExclusive:       if (mSystemExclusiveCallback != NULL)       mSystemExclusiveCallback(mMessage.sysex_array ,mMessage.data1 );  break;
01008             
01009             // Occasional messages
01010         case TimeCodeQuarterFrame:  if (mTimeCodeQuarterFrameCallback != NULL)  mTimeCodeQuarterFrameCallback(mMessage.data1 );  break;
01011         case SongPosition:          if (mSongPositionCallback != NULL)          mSongPositionCallback((mMessage.data1  & 0x7F) | ((mMessage.data2  & 0x7F)<< 7)); break;
01012         case SongSelect:            if (mSongSelectCallback != NULL)            mSongSelectCallback(mMessage.data1 );    break;
01013         case TuneRequest:           if (mTuneRequestCallback != NULL)           mTuneRequestCallback(); break;
01014             
01015         case SystemReset:           if (mSystemResetCallback != NULL)           mSystemResetCallback(); break;
01016         case InvalidType:
01017         default:
01018             break;
01019     }
01020     
01021 }
01022 
01023 
01024 #endif // USE_CALLBACKS
01025 
01026 
01027 #endif // COMPILE_MIDI_IN
01028 
01029 
01030 
01031 
01032 #if (COMPILE_MIDI_IN && COMPILE_MIDI_OUT && COMPILE_MIDI_THRU) // Thru
01033 
01034 /*! \brief Set the filter for thru mirroring
01035  \param inThruFilterMode a filter mode
01036  
01037  @see kThruFilterMode
01038  */
01039 void MIDI::setThruFilterMode(kThruFilterMode  inThruFilterMode)
01040 { 
01041     
01042     mThruFilterMode = inThruFilterMode;
01043     if (mThruFilterMode != Off) mThruActivated = true;
01044     else mThruActivated = false;
01045     
01046 }
01047 
01048 
01049 /*! \brief Setter method: turn message mirroring on. */
01050 void MIDI::turnThruOn(kThruFilterMode  inThruFilterMode)
01051 { 
01052     
01053     mThruActivated = true;
01054     mThruFilterMode = inThruFilterMode;
01055     
01056 }
01057 
01058 
01059 /*! \brief Setter method: turn message mirroring off. */
01060 void MIDI::turnThruOff()
01061 {
01062     
01063     mThruActivated = false; 
01064     mThruFilterMode = Off;
01065     
01066 }
01067 
01068 
01069 // This method is called upon reception of a message and takes care of Thru filtering and sending.
01070 void MIDI::thru_filter(byte  inChannel)
01071 {
01072     
01073     /*
01074      This method handles Soft-Thru filtering.
01075      
01076      Soft-Thru filtering:
01077      - All system messages (System Exclusive, Common and Real Time) are passed to output unless filter is set to Off
01078      - Channel messages are passed to the output whether their channel is matching the input channel and the filter setting
01079      
01080      */
01081     
01082     // If the feature is disabled, don't do anything.
01083     if (!mThruActivated || (mThruFilterMode == Off)) return;
01084     
01085     
01086     // First, check if the received message is Channel
01087     if (mMessage.type  >= NoteOff && mMessage.type  <= PitchBend) {
01088         
01089         const bool filter_condition = ((mMessage.channel  == mInputChannel) || (mInputChannel == MIDI_CHANNEL_OMNI));
01090         
01091         // Now let's pass it to the output
01092         switch (mThruFilterMode) {
01093             case Full:
01094                 send(mMessage.type ,mMessage.data1 ,mMessage.data2 ,mMessage.channel );
01095                 return;
01096             case SameChannel:
01097                 if (filter_condition) {
01098                     send(mMessage.type ,mMessage.data1 ,mMessage.data2 ,mMessage.channel );
01099                     return;
01100                 }
01101                 break;
01102             case DifferentChannel:
01103                 if (!filter_condition) {
01104                     send(mMessage.type ,mMessage.data1 ,mMessage.data2 ,mMessage.channel );
01105                     return;
01106                 }
01107                 break;
01108             case Off:
01109                 // Do nothing. 
01110                 // Technically it's impossible to get there because the case was already tested earlier.
01111                 break;
01112             default:
01113                 break;
01114         }
01115         
01116     }
01117     else {
01118         
01119         // Send the message to the output
01120         switch (mMessage.type ) {
01121                 // Real Time and 1 byte
01122             case Clock:
01123             case Start:
01124             case Stop:
01125             case Continue:
01126             case ActiveSensing:
01127             case SystemReset:
01128             case TuneRequest:   
01129                 sendRealTime(mMessage.type );
01130                 return;
01131                 
01132             case SystemExclusive:
01133                 // Send SysEx (0xF0 and 0xF7 are included in the buffer)
01134                 sendSysEx(mMessage.data1 ,mMessage.sysex_array ,true); 
01135                 return;
01136                 
01137             case SongSelect:
01138                 sendSongSelect(mMessage.data1 );
01139                 return;
01140                 
01141             case SongPosition:
01142                 sendSongPosition(mMessage.data1  | ((unsigned)mMessage.data2 <<7));
01143                 return;
01144                 
01145             case TimeCodeQuarterFrame:
01146                 sendTimeCodeQuarterFrame(mMessage.data1 ,mMessage.data2 );
01147                 return;
01148 
01149             default:
01150                 break;
01151                 
01152         }
01153         
01154     }
01155     
01156 }
01157 
01158 
01159 #endif // Thru