@@ -828,198 +828,199 @@ 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() {
832-
833- if (mTransport .available () == 0 )
834- return false ;
835-
836- mLastError &= ~(1UL << ErrorParse); // Clear ErrorParse bit
837- /* Possible Errors:
838- > SysEx Stop byte received with no pending SysEx Start.
839- > Unsupported Status byte.
840- > Data received without a valid Status byte or Running Status.
841- > Warning SysEx split warning.
842- .... could potentially add an error for when SysEx is aborted due to receiving a new non-realtime status byte.
843- */
844-
845- const byte extracted = mTransport .read ();
846-
847- if (extracted >= 0x80 ) {
848- // Lets try get a valid Status byte. Non-realtime status overides any current Status
849- const MidiType pendingType = getTypeFromStatusByte (extracted);
850- switch (pendingType) {
851- // Realtime
852- case Start:
853- case Continue:
854- case Stop:
855- case Clock:
856- case Tick:
857- case ActiveSensing:
858- case SystemReset:
859- case TuneRequest:
860- // Handle message now
861- mMessage .type = pendingType;
862- mMessage .channel = 0 ;
863- mMessage .data1 = 0 ;
864- mMessage .data2 = 0 ;
865- mMessage .length = 1 ;
866- mMessage .valid = true ;
867- return true ;
868- break ;
869- // 2 byte messages
870- case ProgramChange:
871- case AfterTouchChannel:
872- case TimeCodeQuarterFrame:
873- case SongSelect:
874- mPendingMessage [0 ] = extracted;
875- mPendingMessageExpectedLength = 2 ;
876- break ;
877- // 3 byte messages
878- case NoteOn:
879- case NoteOff:
880- case ControlChange:
881- case PitchBend:
882- case AfterTouchPoly:
883- case SongPosition:
884- mPendingMessage [0 ] = extracted;
885- mPendingMessageExpectedLength = 3 ;
886- break ;
887- // SysEx
888- case SystemExclusiveStart:
889- mPendingMessage [0 ] = SystemExclusive;
890- mPendingMessageExpectedLength = MidiMessage::sSysExMaxSize ;
891- mMessage .sysexArray [0 ] = SystemExclusiveStart;
892- mLastError &= ~(1UL << WarningSplitSysEx); // Reset Warning Split SysEx bit
893- break ;
894- case SystemExclusiveEnd:
895- if (mPendingMessage [0 ] == SystemExclusive) {
896- mMessage .sysexArray [mPendingMessageIndex ++] = SystemExclusiveEnd; // Post Inc pending index here for correct lenght data
897- mMessage .type = SystemExclusive;
898- mMessage .data1 = mPendingMessageIndex & 0xff ; // LSB
899- mMessage .data2 = byte (mPendingMessageIndex >> 8 ); // MSB
900- mMessage .channel = 0 ;
901- mMessage .length = mPendingMessageIndex ;
902- if (mMessage .sysexArray [0 ] == SystemExclusiveEnd) {
903- // This is the last chunk of a split SysEx message, and is NOT a valid SysEx message (it starts with 0xF7)
904- mMessage .valid = false ; // SysEx message is split so this not technically valid
905- launchCallback (); // Lets notify callback to deal with this
906- resetInput (); // Restart message
907- return false ;
908- } else {
909- // We are in a valid SysEx message that hasn't overrun (starts with 0xF0) so lets complete it
910- mMessage .valid = true ;
911- resetInput (); // Restart message
912- return true ;
913- }
914- } else { // Looks like a SysEx End without a Sysex Start
915- mLastError |= 1UL << ErrorParse; // Error: SysEx Stop byte received with no pending SysEx Start.
916- if (mErrorCallback )
917- mErrorCallback (mLastError );
918- resetInput (); // Restart message
919- return false ;
920- }
921- break ;
922- // Unsupported
923- default :
924- mPendingMessage [0 ] = InvalidType;
925- mLastError |= 1UL << ErrorParse; // Error: Unsupported Status byte.
926- if (mErrorCallback )
927- mErrorCallback (mLastError );
928- resetInput (); // Restart message
929- return false ;
930- break ;
931- }
932- mPendingMessageIndex = 1 ; // If we are here, we have a valid Status! Lets try get some Data for it....
933- mRunningStatus_RX = InvalidType; // Lets also reset Running Status until we have a complete message
934- return (Settings::Use1ByteParsing) ? false : parse ();
935-
936- } else {
937- // Lets get some data... First off.. check for Status Byte, or use Running Status
938- if (mPendingMessageIndex == 0 ) {
939- if (mRunningStatus_RX ) {
940- // Yay! We have Running Status
941- mPendingMessage [0 ] = mRunningStatus_RX ;
942- mPendingMessageIndex = 1 ;
943- } else {
944- // ooops.... No Status Byte... No Running Status... lets ignore this data
945- mLastError |= 1UL << ErrorParse; // Error: Data received without a valid Status byte or Running Status.
946- if (mErrorCallback )
947- mErrorCallback (mLastError );
831+ bool MidiInterface<Transport, Settings, Platform>::parse()
832+ {
833+
834+ if (mTransport .available () == 0 )
948835 return false ;
949- }
950- }
951836
952- // Status or Running Status is good so add extracted data byte to pending message
953- if (mPendingMessage [0 ] == SystemExclusive)
954- mMessage .sysexArray [mPendingMessageIndex ] = extracted;
955- else
956- mPendingMessage [mPendingMessageIndex ] = extracted;
957-
958- // Now we are going to check if we have reached the end of the message
959- if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1 )) {
960- // SysEx larger than the allocated buffer size,
961- // Split SysEx like so:
962- // first: 0xF0 .... 0xF0
963- // middle: 0xF7 .... 0xF0
964- // last: 0xF7 .... 0xF7
965- // ***** 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! ****
966- if (mPendingMessage [0 ] == SystemExclusive) {
967- // Warn at start of SysEx split
968- if (mMessage .sysexArray [0 ] == SystemExclusiveStart) {
969- mLastError |= 1UL << WarningSplitSysEx; // We have this error already defined so may as well use it
970- if (mErrorCallback )
971- mErrorCallback (mLastError );
837+ 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+ */
845+
846+ const byte extracted = mTransport .read ();
847+
848+ if (extracted >= 0x80 ) {
849+ // Lets try get a valid Status byte. Non-realtime status overrides any current Status
850+ const MidiType pendingType = getTypeFromStatusByte (extracted);
851+ switch (pendingType) {
852+ // Realtime
853+ case Start:
854+ case Continue:
855+ case Stop:
856+ case Clock:
857+ case Tick:
858+ case ActiveSensing:
859+ case SystemReset:
860+ case TuneRequest:
861+ // Handle message now
862+ mMessage .type = pendingType;
863+ mMessage .channel = 0 ;
864+ mMessage .data1 = 0 ;
865+ mMessage .data2 = 0 ;
866+ mMessage .length = 1 ;
867+ mMessage .valid = true ;
868+ 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
879+ case NoteOn:
880+ case NoteOff:
881+ case ControlChange:
882+ case PitchBend:
883+ case AfterTouchPoly:
884+ case SongPosition:
885+ mPendingMessage [0 ] = extracted;
886+ mPendingMessageExpectedLength = 3 ;
887+ break ;
888+ // SysEx
889+ case SystemExclusiveStart:
890+ mPendingMessage [0 ] = SystemExclusive;
891+ mPendingMessageExpectedLength = MidiMessage::sSysExMaxSize ;
892+ mMessage .sysexArray [0 ] = SystemExclusiveStart;
893+ mLastError &= ~(1UL << WarningSplitSysEx); // Reset Warning Split SysEx bit
894+ break ;
895+ 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 ;
921+ }
922+ break ;
923+ // Unsupported
924+ default :
925+ mPendingMessage [0 ] = InvalidType;
926+ mLastError |= 1UL << ErrorParse; // Error: Unsupported Status byte.
927+ if (mErrorCallback )
928+ mErrorCallback (mLastError );
929+ resetInput (); // Restart message
930+ return false ;
931+ break ;
972932 }
973- auto lastByte = mMessage .sysexArray [Settings::SysExMaxSize - 1 ];
974- mMessage .sysexArray [Settings::SysExMaxSize - 1 ] = SystemExclusiveStart;
975- mMessage .type = SystemExclusive;
976-
977- // Get length
978- mMessage .data1 = Settings::SysExMaxSize & 0xff ; // LSB
979- mMessage .data2 = byte (Settings::SysExMaxSize >> 8 ); // MSB
980- mMessage .channel = 0 ;
981- mMessage .length = Settings::SysExMaxSize;
982- mMessage .valid = false ; // SysEx message is split so this is not technically valid
983-
984- // Notify callback to deal with the SysEx data chunk
985- launchCallback ();
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 ();
986936
987- // Prep next SysEx data chunk to start with 0xF7
988- mMessage .sysexArray [0 ] = SystemExclusiveEnd;
989- mMessage .sysexArray [1 ] = lastByte;
990- mPendingMessageIndex = 2 ;
991- // SysEx buffer has overrun so parse() will no longer return true, and will need to be dealt with via callbacks only
992- return false ;
993- }
937+ } else {
938+ // Lets get some data... First off.. check for Status Byte, or use Running Status
939+ if (mPendingMessageIndex == 0 ) {
940+ if (mRunningStatus_RX ) {
941+ // Yay! We have Running Status
942+ mPendingMessage [0 ] = mRunningStatus_RX ;
943+ mPendingMessageIndex = 1 ;
944+ } 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.
947+ if (mErrorCallback )
948+ mErrorCallback (mLastError );
949+ return false ;
950+ }
951+ }
994952
995- // Pending message is complete so lets save it
996- mMessage .type = getTypeFromStatusByte (mPendingMessage [0 ]);
953+ // Status or Running Status is good so add extracted data byte to pending message
954+ if (mPendingMessage [0 ] == SystemExclusive)
955+ mMessage .sysexArray [mPendingMessageIndex ] = extracted;
956+ else
957+ 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,
962+ // 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
969+ if (mMessage .sysexArray [0 ] == SystemExclusiveStart) {
970+ mLastError |= 1UL << WarningSplitSysEx; // We have this error already defined so may as well use it
971+ if (mErrorCallback )
972+ mErrorCallback (mLastError );
973+ }
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
986+ launchCallback ();
987+
988+ // Prep next SysEx data chunk to start with 0xF7
989+ mMessage .sysexArray [0 ] = SystemExclusiveEnd;
990+ mMessage .sysexArray [1 ] = lastByte;
991+ 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 ;
994+ }
997995
998- if (isChannelMessage (mMessage .type )) {
999- mMessage .channel = getChannelFromStatusByte (mPendingMessage [0 ]);
1000- // Message will be completed soon so lets update RunningStatus now as this is obviously a valid Channel Message.
1001- mRunningStatus_RX = mPendingMessage [0 ];
1002- } else
1003- mMessage .channel = 0 ;
996+ // Pending message is complete so lets save it
997+ mMessage .type = getTypeFromStatusByte (mPendingMessage [0 ]);
1004998
1005- mMessage .data1 = mPendingMessage [1 ];
1006- // Save data2 only if applicable
1007- mMessage .data2 = mPendingMessageExpectedLength == 3 ? mPendingMessage [2 ] : 0 ;
1008- mMessage .length = mPendingMessageExpectedLength ;
1009- mMessage .valid = true ;
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 ;
10101005
1011- // Reset index for next message
1012- mPendingMessageIndex = 0 ;
1013- // mPendingMessageExpectedLength = 0; // <-- No need to reset this as its valid still for Running Status, or will be updated on next Status byte received.
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 ;
10141011
1015- return true ;
1016- } else {
1017- // We need more data...
1018- mPendingMessageIndex ++;
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.
10191015
1020- return (Settings::Use1ByteParsing) ? false : parse ();
1016+ return true ;
1017+ } else {
1018+ // We need more data...
1019+ mPendingMessageIndex ++;
1020+
1021+ return (Settings::Use1ByteParsing) ? false : parse ();
1022+ }
10211023 }
1022- }
10231024}
10241025
10251026// Private method, see midi_Settings.h for documentation
0 commit comments