X-TOUCH to djay bridge
Dependencies: mbed mbed-rtos FATFileSystem
MIDI.cpp
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
Generated on Wed Jul 13 2022 10:54:56 by 1.7.2