00001
00011 #include "MIDI.h"
00012 #include <stdlib.h>
00013 #include "WConstants.h"
00014 #include "HardwareSerial.h"
00015
00016
00018 MIDI_Class MIDI;
00019
00020
00022 MIDI_Class::MIDI_Class() { }
00026 MIDI_Class::~MIDI_Class() { }
00027
00028
00034 void MIDI_Class::begin(const byte inChannel) {
00035
00036
00037 USE_SERIAL_PORT.begin(MIDI_BAUDRATE);
00038
00039
00040 #if COMPFLAG_MIDI_OUT
00041
00042 #if USE_RUNNING_STATUS
00043 mRunningStatus_TX = InvalidType;
00044 #endif // USE_RUNNING_STATUS
00045
00046 #endif // COMPFLAG_MIDI_OUT
00047
00048
00049 #if COMPFLAG_MIDI_IN
00050
00051 mInputChannel = inChannel;
00052 mRunningStatus_RX = InvalidType;
00053 mPendingMessageIndex = 0;
00054 mPendingMessageExpectedLenght = 0;
00055
00056 mMessage.valid = false;
00057 mMessage.type = InvalidType;
00058 mMessage.channel = 0;
00059 mMessage.data1 = 0;
00060 mMessage.data2 = 0;
00061
00062 #endif // COMPFLAG_MIDI_IN
00063
00064
00065 #if (COMPFLAG_MIDI_IN && COMPFLAG_MIDI_OUT) // Thru
00066
00067 mThruFilterMode = Full;
00068
00069 #endif // Thru
00070
00071 }
00072
00073
00074 #if COMPFLAG_MIDI_OUT
00075
00076
00077 const byte MIDI_Class::genstatus(const kMIDIType inType,const byte inChannel) {
00078 return ((byte)inType | ((inChannel-1) & 0x0F));
00079 }
00080
00081
00082
00083
00084
00085
00086
00087 void MIDI_Class::send(kMIDIType type, byte data1, byte data2, byte channel) {
00088
00089
00090 if (channel >= MIDI_CHANNEL_OFF || channel == MIDI_CHANNEL_OMNI) {
00091
00092 #if USE_RUNNING_STATUS
00093 mRunningStatus_TX = InvalidType;
00094 #endif
00095
00096 return;
00097 }
00098
00099 switch (type) {
00100
00101 case NoteOff:
00102 case NoteOn:
00103 case ProgramChange:
00104 case ControlChange:
00105 case PitchBend:
00106 case AfterTouchPoly:
00107 case AfterTouchChannel:
00108 {
00109
00110
00111 data1 &= 0x7F;
00112 data2 &= 0x7F;
00113
00114 byte statusbyte = genstatus(type,channel);
00115
00116 #if USE_RUNNING_STATUS
00117
00118 if (mRunningStatus_TX != statusbyte) {
00119
00120 mRunningStatus_TX = statusbyte;
00121 USE_SERIAL_PORT.write(mRunningStatus_TX);
00122 }
00123 #else
00124
00125 USE_SERIAL_PORT.write(statusbyte);
00126 #endif
00127
00128
00129 USE_SERIAL_PORT.write(data1);
00130 if (type != ProgramChange && type != AfterTouchChannel) {
00131 USE_SERIAL_PORT.write(data2);
00132 }
00133 }
00134 break;
00135
00136
00137 case Clock:
00138 case Start:
00139 case Stop:
00140 case Continue:
00141 case ActiveSensing:
00142 case SystemReset:
00143 case TuneRequest:
00144 sendRealTime(type);
00145 break;
00146
00147 default:
00148 break;
00149 }
00150
00151
00152 }
00153
00159 void MIDI_Class::sendNoteOn(byte NoteNumber,byte Velocity,byte Channel) { send(NoteOn,NoteNumber,Velocity,Channel); }
00160
00166 void MIDI_Class::sendNoteOff(byte NoteNumber,byte Velocity,byte Channel) { send(NoteOff,NoteNumber,Velocity,Channel); }
00167
00172 void MIDI_Class::sendProgramChange(byte ProgramNumber,byte Channel) { send(ProgramChange,ProgramNumber,0,Channel); }
00173
00179 void MIDI_Class::sendControlChange(byte ControlNumber, byte ControlValue,byte Channel) { send(ControlChange,ControlNumber,ControlValue,Channel); }
00180
00186 void MIDI_Class::sendPolyPressure(byte NoteNumber,byte Pressure,byte Channel) { send(AfterTouchPoly,NoteNumber,Pressure,Channel); }
00187
00192 void MIDI_Class::sendAfterTouch(byte Pressure,byte Channel) { send(AfterTouchChannel,Pressure,0,Channel); }
00193
00198 void MIDI_Class::sendPitchBend(unsigned int PitchValue,byte Channel) {
00199
00200 send(PitchBend,(PitchValue & 0x7F),(PitchValue >> 7) & 0x7F,Channel);
00201
00202 }
00207 void MIDI_Class::sendPitchBend(double PitchValue,byte Channel) {
00208
00209 unsigned int pitchval = (PitchValue+1.f)*8192;
00210 if (pitchval > 16383) pitchval = 16383;
00211 sendPitchBend(pitchval,Channel);
00212
00213 }
00214
00221 void MIDI_Class::sendSysEx(byte length, byte * array, bool ArrayContainsBoundaries) {
00222 if (!ArrayContainsBoundaries) USE_SERIAL_PORT.write(0xF0);
00223 for (byte i=0;i<length;i++) USE_SERIAL_PORT.write(array[i]);
00224 if (!ArrayContainsBoundaries) USE_SERIAL_PORT.write(0xF7);
00225 }
00226
00228 void MIDI_Class::sendTuneRequest() { sendRealTime(TuneRequest); }
00229
00234 void MIDI_Class::sendTimeCodeQuarterFrame(byte TypeNibble, byte ValuesNibble) {
00235
00236 byte data = ( ((TypeNibble & 0x07) << 4) | (ValuesNibble & 0x0F) );
00237 sendTimeCodeQuarterFrame(data);
00238
00239 }
00240
00244 void MIDI_Class::sendTimeCodeQuarterFrame(byte data) {
00245
00246 USE_SERIAL_PORT.write((byte)TimeCodeQuarterFrame);
00247 USE_SERIAL_PORT.write(data);
00248
00249 }
00250
00254 void MIDI_Class::sendSongPosition(unsigned int Beats) {
00255
00256 USE_SERIAL_PORT.write((byte)SongPosition);
00257 USE_SERIAL_PORT.write(Beats & 0x7F);
00258 USE_SERIAL_PORT.write((Beats >> 7) & 0x7F);
00259
00260 }
00261
00263 void MIDI_Class::sendSongSelect(byte SongNumber) {
00264
00265 USE_SERIAL_PORT.write((byte)SongSelect);
00266 USE_SERIAL_PORT.write(SongNumber & 0x7F);
00267
00268 }
00269
00273 void MIDI_Class::sendRealTime(kMIDIType Type) {
00274 switch (Type) {
00275 case TuneRequest:
00276 case Clock:
00277 case Start:
00278 case Stop:
00279 case Continue:
00280 case ActiveSensing:
00281 case SystemReset:
00282 USE_SERIAL_PORT.write((byte)Type);
00283 break;
00284 default:
00285
00286 break;
00287 }
00288 }
00289
00290 #endif // COMPFLAG_MIDI_OUT
00291
00292
00293
00294 #if COMPFLAG_MIDI_IN
00295
00301 bool MIDI_Class::read() {
00302 return read(mInputChannel);
00303 }
00304
00306 bool MIDI_Class::read(const byte inChannel) {
00307
00308 if (inChannel >= MIDI_CHANNEL_OFF) return false;
00309
00310 if (parse(inChannel)) return filter(inChannel);
00311 else return false;
00312
00313 }
00314
00315
00316 bool MIDI_Class::parse(byte inChannel) {
00317
00318
00319 if (USE_SERIAL_PORT.available() == 128) {
00320 USE_SERIAL_PORT.flush();
00321 }
00322
00323 if (USE_SERIAL_PORT.available() <= 0) {
00324
00325 return false;
00326 }
00327 else {
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 byte extracted = USE_SERIAL_PORT.read();
00339
00340 if (mPendingMessageIndex == 0) {
00341 mPendingMessage[0] = extracted;
00342
00343
00344 switch (getTypeFromStatusByte(mRunningStatus_RX)) {
00345
00346 case NoteOff:
00347 case NoteOn:
00348 case AfterTouchPoly:
00349 case ControlChange:
00350 case ProgramChange:
00351 case AfterTouchChannel:
00352 case PitchBend:
00353
00354
00355 if (extracted < 0x80) {
00356 mPendingMessage[0] = mRunningStatus_RX;
00357 mPendingMessage[1] = extracted;
00358 mPendingMessageIndex = 1;
00359 }
00360
00361
00362
00363 break;
00364
00365 default:
00366
00367 break;
00368 }
00369
00370
00371 switch (getTypeFromStatusByte(mPendingMessage[0])) {
00372
00373
00374 case Start:
00375 case Continue:
00376 case Stop:
00377 case Clock:
00378 case ActiveSensing:
00379 case SystemReset:
00380 case TuneRequest:
00381
00382 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
00383 mMessage.channel = 0;
00384 mMessage.data1 = 0;
00385 mMessage.data2 = 0;
00386 mMessage.valid = true;
00387 mPendingMessageExpectedLenght = 0;
00388 mPendingMessageIndex = 0;
00389 mRunningStatus_RX = InvalidType;
00390 return true;
00391 break;
00392
00393
00394 case ProgramChange:
00395 case AfterTouchChannel:
00396 case TimeCodeQuarterFrame:
00397 case SongSelect:
00398 mPendingMessageExpectedLenght = 2;
00399 break;
00400
00401
00402 case NoteOn:
00403 case NoteOff:
00404 case ControlChange:
00405 case PitchBend:
00406 case AfterTouchPoly:
00407 case SongPosition:
00408 mPendingMessageExpectedLenght = 3;
00409 break;
00410
00411 case SystemExclusive:
00412 mPendingMessageExpectedLenght = MIDI_SYSEX_ARRAY_SIZE;
00413 break;
00414
00415 case InvalidType:
00416 default:
00417
00418 mPendingMessageIndex = 0;
00419 mPendingMessageExpectedLenght = 0;
00420 mRunningStatus_RX = InvalidType;
00421 return false;
00422 break;
00423 }
00424
00425
00426 mPendingMessageIndex++;
00427
00428
00429 return parse(inChannel);
00430
00431 }
00432 else {
00433
00434
00435
00436 if (extracted >= 0x80) {
00437
00438
00439 switch (extracted) {
00440 case Clock:
00441 case Start:
00442 case Continue:
00443 case Stop:
00444 case ActiveSensing:
00445 case SystemReset:
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 mMessage.type = (kMIDIType)extracted;
00458 mMessage.data1 = 0;
00459 mMessage.data2 = 0;
00460 mMessage.channel = 0;
00461 mMessage.valid = true;
00462 return true;
00463
00464 break;
00465
00466
00467 case 0xF7:
00468 if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
00469
00470
00471 for (byte i=0;i<MIDI_SYSEX_ARRAY_SIZE;i++) {
00472 mMessage.sysex_array[i] = mPendingMessage[i];
00473 }
00474
00475 mMessage.type = SystemExclusive;
00476 mMessage.data1 = mPendingMessageIndex+1;
00477 mMessage.data2 = 0;
00478 mMessage.channel = 0;
00479 mMessage.valid = true;
00480
00481 mPendingMessageIndex = 0;
00482 mPendingMessageExpectedLenght = 0;
00483 mRunningStatus_RX = InvalidType;
00484
00485 return true;
00486 }
00487 else {
00488
00489 mPendingMessageIndex = 0;
00490 mPendingMessageExpectedLenght = 0;
00491 mRunningStatus_RX = InvalidType;
00492 return false;
00493 }
00494
00495 break;
00496 default:
00497 break;
00498 }
00499
00500
00501
00502 }
00503
00504
00505
00506 mPendingMessage[mPendingMessageIndex] = extracted;
00507
00508
00509
00510 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght-1)) {
00511
00512
00513
00514
00515 if (getTypeFromStatusByte(mPendingMessage[0]) == SystemExclusive) {
00516 mPendingMessageIndex = 0;
00517 mPendingMessageExpectedLenght = 0;
00518 mRunningStatus_RX = InvalidType;
00519 return false;
00520 }
00521
00522
00523
00524
00525 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
00526 mMessage.channel = (mPendingMessage[0] & 0x0F)+1;
00527
00528 mMessage.data1 = mPendingMessage[1];
00529 mMessage.data2 = mPendingMessage[2];
00530
00531
00532 mPendingMessageIndex = 0;
00533 mPendingMessageExpectedLenght = 0;
00534
00535 mMessage.valid = true;
00536
00537
00538 switch (mMessage.type) {
00539 case NoteOff:
00540 case NoteOn:
00541 case AfterTouchPoly:
00542 case ControlChange:
00543 case ProgramChange:
00544 case AfterTouchChannel:
00545 case PitchBend:
00546
00547 mRunningStatus_RX = mPendingMessage[0];
00548 break;
00549
00550 default:
00551
00552 mRunningStatus_RX = InvalidType;
00553 break;
00554 }
00555 return true;
00556 }
00557 else {
00558
00559 mPendingMessageIndex++;
00560
00561
00562 return parse(inChannel);
00563 }
00564
00565 }
00566
00567
00568 }
00569
00570
00571 return false;
00572 }
00573
00574
00575
00577 kMIDIType MIDI_Class::getType() { return mMessage.type; }
00579 byte MIDI_Class::getChannel() { return mMessage.channel; }
00581 byte MIDI_Class::getData1() { return mMessage.data1; }
00583 byte MIDI_Class::getData2() { return mMessage.data2; }
00585 byte * MIDI_Class::getSysExArray() { return mMessage.sysex_array; }
00587 bool MIDI_Class::check() { return mMessage.valid; }
00588
00589
00594 void MIDI_Class::setInputChannel(const byte Channel) { mInputChannel = Channel; }
00595
00596
00597 #endif // COMPFLAG_MIDI_IN
00598
00599
00600
00601
00602 #if (COMPFLAG_MIDI_IN && COMPFLAG_MIDI_OUT) // Thru
00603
00608 void MIDI_Class::setThruFilterMode(kThruFilterMode inThruFilterMode) {
00609 mThruFilterMode = inThruFilterMode;
00610 if (mThruFilterMode != Off) mThruActivated = true;
00611 else mThruActivated = false;
00612 }
00618 void MIDI_Class::setThruFilterMode(byte inThruFilterMode) {
00619 mThruFilterMode = (kThruFilterMode)inThruFilterMode;
00620 if (mThruFilterMode != Off) mThruActivated = true;
00621 else mThruActivated = false;
00622 }
00623
00624
00626 void MIDI_Class::turnThruOn(kThruFilterMode inThruFilterMode) {
00627 mThruActivated = true;
00628 mThruFilterMode = inThruFilterMode;
00629 }
00631 void MIDI_Class::turnThruOff() {
00632 mThruActivated = false;
00633 mThruFilterMode = Off;
00634 }
00635
00636
00637
00638
00639 bool MIDI_Class::filter(byte inChannel) {
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651 bool validate_message = false;
00652
00653
00654 if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) {
00655
00656
00657 if ((mMessage.channel == mInputChannel) || (mInputChannel == MIDI_CHANNEL_OMNI)) {
00658 validate_message = true;
00659
00660 }
00661 else {
00662
00663 validate_message = false;
00664 }
00665
00666
00667 switch (mThruFilterMode) {
00668 case Full:
00669 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
00670 break;
00671 case SameChannel:
00672 if (validate_message) {
00673 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
00674 }
00675 break;
00676 case DifferentChannel:
00677 if (!validate_message) {
00678 send(mMessage.type,mMessage.data1,mMessage.data2,mMessage.channel);
00679 }
00680 case Off:
00681
00682 break;
00683 default:
00684 break;
00685 }
00686
00687 }
00688 else {
00689
00690
00691 validate_message = true;
00692
00693
00694 if (mThruFilterMode != Off) {
00695 switch (mMessage.type) {
00696
00697 case Clock:
00698 case Start:
00699 case Stop:
00700 case Continue:
00701 case ActiveSensing:
00702 case SystemReset:
00703 case TuneRequest:
00704 sendRealTime(mMessage.type);
00705 break;
00706
00707 case SystemExclusive:
00708
00709 sendSysEx(mMessage.data1,mMessage.sysex_array,true);
00710 break;
00711
00712 case SongSelect:
00713 sendSongSelect(mMessage.data1);
00714 break;
00715
00716 case SongPosition:
00717 sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2<<7));
00718 break;
00719
00720 case TimeCodeQuarterFrame:
00721 sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);
00722 break;
00723 default:
00724 break;
00725 }
00726
00727 }
00728
00729 }
00730
00731
00732
00733
00734 return validate_message;
00735 }
00736
00737
00738 #endif // Thru
00739
00740