@@ -828,198 +828,164 @@ inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel
828828
829829// Private method: MIDI parser
830830template <class Transport , class Settings , class Platform >
831- bool MidiInterface<Transport, Settings, Platform>::parse()
831+ bool MidiInterface<Transport, Settings, Platform>::parse()
832832{
833833
834834 if (mTransport .available () == 0 )
835835 return false ;
836836
837837 mLastError &= ~(1UL << ErrorParse); // Clear ErrorParse bit
838- /* Possible Errors:
839- > SysEx Stop byte received with no pending SysEx Start.
840- > Unsupported Status byte.
841- > Data received without a valid Status byte or Running Status.
842- > Warning SysEx split warning.
843- .... could potentially add an error for when SysEx is aborted due to receiving a new non-realtime status byte.
844- */
845838
846839 const byte extracted = mTransport .read ();
847840
848841 if (extracted >= 0x80 ) {
849- // Lets try get a valid Status byte. Non-realtime status overrides any current Status
850- const MidiType pendingType = getTypeFromStatusByte (extracted);
842+ // Get Status including Undefined ones so we can properly deal with them
843+ const MidiType pendingType = extracted < 0xF0 ? MidiType (extracted & 0xF0 ) : MidiType (extracted);
851844 switch (pendingType) {
852- // Realtime
845+ // One byte realtime will complete now
853846 case Start:
854847 case Continue:
855848 case Stop:
856849 case Clock:
857- case Tick:
850+ case Tick: // <---- Is tick relevant anymore?? .... Not part of the MIDI spec
858851 case ActiveSensing:
859852 case SystemReset:
860- case TuneRequest:
861- // Handle message now
853+ // Might as well quickly deal with these now.
862854 mMessage .type = pendingType;
863855 mMessage .channel = 0 ;
864856 mMessage .data1 = 0 ;
865857 mMessage .data2 = 0 ;
866858 mMessage .length = 1 ;
867859 mMessage .valid = true ;
868860 return true ;
869- break ;
870- // 2 byte messages
871- case ProgramChange:
872- case AfterTouchChannel:
873- case TimeCodeQuarterFrame:
874- case SongSelect:
875- mPendingMessage [0 ] = extracted;
876- mPendingMessageExpectedLength = 2 ;
877- break ;
878- // 3 byte messages
879861 case NoteOn:
880862 case NoteOff:
881863 case ControlChange:
882864 case PitchBend:
883865 case AfterTouchPoly:
884866 case SongPosition:
885- mPendingMessage [0 ] = extracted;
886867 mPendingMessageExpectedLength = 3 ;
887868 break ;
888- // SysEx
869+ case ProgramChange:
870+ case AfterTouchChannel:
871+ case TimeCodeQuarterFrame:
872+ case SongSelect:
873+ mPendingMessageExpectedLength = 2 ;
874+ mPendingMessage [2 ] = 0 ; // Zero unused data
875+ break ;
876+ // One byte common will be completed this run (This will also reset running status as this is not realtime)
877+ case TuneRequest:
878+ mPendingMessageExpectedLength = 1 ;
879+ mPendingMessage [1 ] = 0 ; // Zero unused data
880+ mPendingMessage [2 ] = 0 ; // Zero unused data
881+ break ;
889882 case SystemExclusiveStart:
890- mPendingMessage [0 ] = SystemExclusive;
891883 mPendingMessageExpectedLength = MidiMessage::sSysExMaxSize ;
892884 mMessage .sysexArray [0 ] = SystemExclusiveStart;
893- mLastError &= ~(1UL << WarningSplitSysEx); // Reset Warning Split SysEx bit
894885 break ;
895886 case SystemExclusiveEnd:
896- if (mPendingMessage [0 ] == SystemExclusive) {
897- mMessage .sysexArray [mPendingMessageIndex ++] = SystemExclusiveEnd; // Post Inc pending index here for correct length data
898- mMessage .type = SystemExclusive;
899- mMessage .data1 = mPendingMessageIndex & 0xff ; // LSB
900- mMessage .data2 = byte (mPendingMessageIndex >> 8 ); // MSB
901- mMessage .channel = 0 ;
902- mMessage .length = mPendingMessageIndex ;
903- if (mMessage .sysexArray [0 ] == SystemExclusiveEnd) {
904- // This is the last chunk of a split SysEx message, and is NOT a valid SysEx message (it starts with 0xF7)
905- mMessage .valid = false ; // SysEx message is split so this is not technically valid
906- launchCallback (); // Lets notify callback to deal with this
907- resetInput (); // Restart message
908- return false ;
909- } else {
910- // We are in a valid SysEx message that hasn't overrun (starts with 0xF0) so lets complete it
911- mMessage .valid = true ;
912- resetInput (); // Restart message
913- return true ;
914- }
915- } else { // Looks like a SysEx End without a Sysex Start
916- mLastError |= 1UL << ErrorParse; // Error: SysEx Stop byte received with no pending SysEx Start.
917- if (mErrorCallback )
918- mErrorCallback (mLastError );
919- resetInput (); // Restart message
920- return false ;
887+ if (mPendingMessage [0 ] == SystemExclusiveStart) { // If were currently doing SysEx
888+ mPendingMessageExpectedLength = ++mPendingMessageIndex ; // Update expected lenght as we have an EOX and within Buffer
889+ break ;
921890 }
922- break ;
923- // Unsupported
924891 default :
925- mPendingMessage [0 ] = InvalidType;
926- mLastError |= 1UL << ErrorParse; // Error: Unsupported Status byte.
892+ mLastError |= 1UL << ErrorParse; // Error: Undefined Status or stray EOX
927893 if (mErrorCallback )
928894 mErrorCallback (mLastError );
929- resetInput (); // Restart message
895+ if ((pendingType != Undefined_F9) && (pendingType != Undefined_FD)) { // Dont reset for 0xFD & 0xF9 (Undefined Realtime)
896+ resetInput (); // Input reset for stray EOX and Undefined common F4/F5
897+ }
930898 return false ;
931- break ;
932899 }
933- mPendingMessageIndex = 1 ; // If we are here, we have a valid Status! Lets try get some Data for it....
934- mRunningStatus_RX = InvalidType ; // Lets also reset Running Status until we have a complete message
935- return (Settings::Use1ByteParsing) ? false : parse ();
900+ mRunningStatus_RX = InvalidType ; // Reset Running Status until valid channel message complete
901+ mPendingMessage [ 0 ] = extracted ; // Status seems good so lets store in pending
902+ if (extracted != SystemExclusiveEnd) mPendingMessageIndex = 1 ; // Set PendingMessageIndex to 1 (needs to be unchanged for EOX)
936903
937904 } else {
938- // Lets get some data... First off.. check for Status Byte, or use Running Status
905+ // Check Status
939906 if (mPendingMessageIndex == 0 ) {
940907 if (mRunningStatus_RX ) {
941- // Yay! We have Running Status
942908 mPendingMessage [0 ] = mRunningStatus_RX ;
943909 mPendingMessageIndex = 1 ;
944910 } else {
945- // ooops.... No Status Byte... No Running Status... lets ignore this data
946- mLastError |= 1UL << ErrorParse; // Error: Data received without a valid Status byte or Running Status.
911+ mLastError |= 1UL << ErrorParse; // Error: No Status
947912 if (mErrorCallback )
948913 mErrorCallback (mLastError );
949914 return false ;
950915 }
951916 }
952-
953- // Status or Running Status is good so add extracted data byte to pending message
917+ // Add Data
954918 if (mPendingMessage [0 ] == SystemExclusive)
955919 mMessage .sysexArray [mPendingMessageIndex ] = extracted;
956920 else
957921 mPendingMessage [mPendingMessageIndex ] = extracted;
958-
959- // Now we are going to check if we have reached the end of the message
960- if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1 )) {
961- // SysEx larger than the allocated buffer size,
922+ mPendingMessageIndex ++;
923+ }
924+ // Check for a complete message
925+ if (mPendingMessageIndex >= mPendingMessageExpectedLength ) {
926+ // Process SysEx
927+ if (mPendingMessage [0 ] == SystemExclusiveStart || mPendingMessage [0 ] == SystemExclusiveEnd) {
928+
929+ mMessage .type = SystemExclusive;
930+ mMessage .data1 = mPendingMessageIndex & 0xff ; // LSB
931+ mMessage .data2 = byte (mPendingMessageIndex >> 8 ); // MSB
932+ mMessage .channel = 0 ;
933+ mMessage .length = mPendingMessageIndex ;
934+
935+ // SysEx can be larger than the allocated buffer size (must handle with callbacks only)
962936 // Split SysEx like so:
963- // first: 0xF0 .... 0xF0
964- // middle: 0xF7 .... 0xF0
965- // last: 0xF7 .... 0xF7
966- // ***** If the buffer has overrun, this SysEx message can now no longer be considered a valid Midi message and must be dealt with via callbacks only! ****
967- if (mPendingMessage [0 ] == SystemExclusive) {
968- // Warn at start of SysEx split
937+ // first: 0xF0 .... 0xF0
938+ // midlle: 0xF7 .... 0xF0
939+ // last: 0xF7 .... 0xF7
940+
941+ // SysEx buffer not full... EOX
942+ if (mPendingMessage [0 ] == SystemExclusiveEnd) {
943+ mMessage .sysexArray [mPendingMessageIndex - 1 ] = SystemExclusiveEnd;
944+ mPendingMessageIndex = 0 ;
945+ if (mMessage .sysexArray [0 ] == SystemExclusiveEnd) { // This is the last chunk of split SysEx
946+ mMessage .valid = false ;
947+ launchCallback ();
948+ } else { // Not Split SysEx
949+ mMessage .valid = true ;
950+ }
951+ } else { // SysEx buffer full
969952 if (mMessage .sysexArray [0 ] == SystemExclusiveStart) {
970- mLastError |= 1UL << WarningSplitSysEx; // We have this error already defined so may as well use it
971953 if (mErrorCallback )
972- mErrorCallback (mLastError );
954+ mErrorCallback (1UL << WarningSplitSysEx); // Notify but no need to store this warning?
973955 }
974- auto lastByte = mMessage .sysexArray [Settings::SysExMaxSize - 1 ];
975- mMessage .sysexArray [Settings::SysExMaxSize - 1 ] = SystemExclusiveStart;
976- mMessage .type = SystemExclusive;
977-
978- // Get length
979- mMessage .data1 = Settings::SysExMaxSize & 0xff ; // LSB
980- mMessage .data2 = byte (Settings::SysExMaxSize >> 8 ); // MSB
981- mMessage .channel = 0 ;
982- mMessage .length = Settings::SysExMaxSize;
983- mMessage .valid = false ; // SysEx message is split so this is not technically valid
984-
985- // Notify callback to deal with the SysEx data chunk
956+ byte lastByte = mMessage .sysexArray [Settings::SysExMaxSize - 1 ]; // <--- change from Settings::SysExMaxSize to mPendingMessageIndex?
957+ mMessage .sysexArray [Settings::SysExMaxSize - 1 ] = SystemExclusiveStart; // <--- change from Settings::SysExMaxSize to mPendingMessageIndex?
958+ mMessage .valid = false ;
986959 launchCallback ();
987960
988961 // Prep next SysEx data chunk to start with 0xF7
989962 mMessage .sysexArray [0 ] = SystemExclusiveEnd;
990963 mMessage .sysexArray [1 ] = lastByte;
991964 mPendingMessageIndex = 2 ;
992- // SysEx buffer has overrun so parse() will no longer return true, and will need to be dealt with via callbacks only
993- return false ;
994965 }
995966
996- // Pending message is complete so lets save it
997- mMessage .type = getTypeFromStatusByte (mPendingMessage [0 ]);
998-
999- if (isChannelMessage (mMessage .type )) {
1000- mMessage .channel = getChannelFromStatusByte (mPendingMessage [0 ]);
1001- // Message will be completed soon so lets update RunningStatus now as this is obviously a valid Channel Message.
1002- mRunningStatus_RX = mPendingMessage [0 ];
1003- } else
1004- mMessage .channel = 0 ;
1005-
1006- mMessage .data1 = mPendingMessage [1 ];
1007- // Save data2 only if applicable
1008- mMessage .data2 = mPendingMessageExpectedLength == 3 ? mPendingMessage [2 ] : 0 ;
1009- mMessage .length = mPendingMessageExpectedLength ;
1010- mMessage .valid = true ;
1011-
1012- // Reset index for next message
1013- mPendingMessageIndex = 0 ;
1014- // mPendingMessageExpectedLength = 0; // <-- No need to reset this as its valid still for Running Status, or will be updated on next Status byte received.
967+ return mMessage .valid ;
968+ }
1015969
1016- return true ;
1017- } else {
1018- // We need more data...
1019- mPendingMessageIndex ++;
970+ // Process message
971+ mMessage .type = getTypeFromStatusByte (mPendingMessage [0 ]);
972+ if (isChannelMessage (mMessage .type )) {
973+ mMessage .channel = (mPendingMessage [0 ] & 0x0F ) + 1 ;
974+ mRunningStatus_RX = mPendingMessage [0 ];
975+ } else
976+ mMessage .channel = 0 ;
977+ mMessage .data1 = mPendingMessage [1 ];
978+ mMessage .data2 = mPendingMessage [2 ];
979+ mMessage .length = mPendingMessageExpectedLength ;
980+ mMessage .valid = true ;
981+
982+ // Reset index for next message
983+ mPendingMessageIndex = 0 ;
1020984
1021- return (Settings::Use1ByteParsing) ? false : parse ();
1022- }
985+ return true ;
986+ } else {
987+ // We need more input...
988+ return (Settings::Use1ByteParsing) ? false : parse ();
1023989 }
1024990}
1025991
0 commit comments