LCOV - code coverage report
Current view: top level - src/MIDI_Parsers - USBMIDI_Parser.cpp (source / functions) Hit Total Coverage
Test: e224b347cd670555e44f06608ac41bd1ace9d9d8 Lines: 58 66 87.9 %
Date: 2020-09-08 17:44:46 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "USBMIDI_Parser.hpp"
       2             : #include <Settings/SettingsWrapper.hpp>
       3             : 
       4             : BEGIN_CS_NAMESPACE
       5             : 
       6             : // https://usb.org/sites/default/files/midi10.pdf
       7          40 : MIDIReadEvent USBMIDI_Parser::parse(uint8_t *packet) {
       8          40 :     DEBUG("MIDIUSB packet:\t" << hex << packet[0] << ' ' << packet[1] << ' '
       9             :                               << packet[2] << ' ' << packet[3] << dec);
      10             :     // MIDI USB cable number
      11          40 :     uint8_t CN = packet[0] >> 4;
      12             :     // MIDI USB code index number
      13          40 :     MIDICodeIndexNumber CIN = static_cast<MIDICodeIndexNumber>(packet[0] & 0xF);
      14             : 
      15             :     // SysEx constants
      16          40 :     constexpr uint8_t SysExEnd =
      17             :         static_cast<uint8_t>(MIDIMessageType::SYSEX_END);
      18          40 :     constexpr uint8_t SysExStart =
      19             :         static_cast<uint8_t>(MIDIMessageType::SYSEX_START);
      20             : 
      21             :     // Main parser logic
      22             :     // =========================================================================
      23             : 
      24             :     // ------------------- Channel message (2 or 3 bytes) ------------------- //
      25             : 
      26          40 :     if (CIN >= MIDICodeIndexNumber::NOTE_OFF &&
      27           9 :         CIN <= MIDICodeIndexNumber::PITCH_BEND) {
      28             :         // 2- or 3-byte MIDI channel message
      29             : 
      30             :         // uint8_t type = packet[1] & 0xF0;
      31             :         // if (CIN != type) // invalid MIDI USB packet
      32             :         //    return NO_MESSAGE;
      33           6 :         midimsg.header = packet[1];
      34           6 :         midimsg.data1 = packet[2];
      35           6 :         midimsg.data2 = packet[3];
      36           6 :         midimsg.CN = CN;
      37           6 :         return MIDIReadEvent::CHANNEL_MESSAGE;
      38             :     }
      39             : 
      40             :     // ---------------- SysEx starts or continues (3 bytes) ----------------- //
      41             : 
      42             : #if !IGNORE_SYSEX
      43          34 :     else if (CIN == MIDICodeIndexNumber::SYSEX_START_CONT) {
      44             :         // SysEx starts or continues (3 bytes)
      45          16 :         if (packet[1] == SysExStart)
      46           9 :             startSysEx(CN); // start a new message
      47             :                             // (overwrite previous unfinished message)
      48           7 :         else if (!receivingSysEx(CN)) { // If we haven't received a SysExStart
      49           0 :             DEBUGREF(F("Error: No SysExStart received"));
      50           0 :             return MIDIReadEvent::NO_MESSAGE; // ignore the data
      51             :         }
      52          16 :         addSysExByte(CN, packet[1]) &&     // add three data bytes to buffer
      53          16 :             addSysExByte(CN, packet[2]) && //
      54          16 :             addSysExByte(CN, packet[3]);
      55          16 :         return MIDIReadEvent::NO_MESSAGE; // SysEx is not finished yet
      56             :     }
      57             : 
      58             :     // --------------- SysEx ends with following single byte ---------------- //
      59             : 
      60          18 :     else if (CIN == MIDICodeIndexNumber::SYSEX_END_1B) {
      61             :         // SysEx ends with following single byte
      62             :         // (or Single-byte System Common Message, not implemented)
      63           5 :         if (packet[1] != SysExEnd) {
      64             :             // System Common (not implemented)
      65           0 :             return MIDIReadEvent::NO_MESSAGE;
      66           5 :         } else if (!receivingSysEx(CN)) { // If we haven't received a SysExStart
      67           1 :             DEBUGFN(F("Error: No SysExStart received"));
      68           1 :             return MIDIReadEvent::NO_MESSAGE; // ignore the data
      69             :         }
      70           4 :         if (addSysExByte(CN, packet[1])) {
      71           4 :             endSysEx(CN);
      72           4 :             return MIDIReadEvent::SYSEX_MESSAGE;
      73             :         } else {
      74           0 :             return MIDIReadEvent::NO_MESSAGE; // Buffer full, ignore message
      75             :         }
      76             :     }
      77             : 
      78             :     // ---------------- SysEx ends with following two bytes ----------------- //
      79             : 
      80          13 :     else if (CIN == MIDICodeIndexNumber::SYSEX_END_2B) {
      81             :         // SysEx ends with following two bytes
      82           5 :         if (packet[1] == SysExStart)
      83           1 :             startSysEx(CN); // start a new message
      84             :         // (overwrite previous unfinished message)
      85           4 :         else if (!receivingSysEx(CN)) { // If we haven't received a SysExStart
      86           1 :             DEBUGFN(F("Error: No SysExStart received"));
      87           1 :             return MIDIReadEvent::NO_MESSAGE; // ignore the data
      88             :         }
      89             :         if ( // add two data bytes to buffer
      90           4 :             addSysExByte(CN, packet[1]) && addSysExByte(CN, SysExEnd)) {
      91           4 :             endSysEx(CN);
      92           4 :             return MIDIReadEvent::SYSEX_MESSAGE;
      93             :         } else
      94           0 :             return MIDIReadEvent::NO_MESSAGE; // Buffer full, ignore message
      95             :     }
      96             : 
      97             :     // --------------- SysEx ends with following three bytes ---------------- //
      98             : 
      99           8 :     else if (CIN == MIDICodeIndexNumber::SYSEX_END_3B) {
     100             :         // SysEx ends with following three bytes
     101           5 :         if (packet[1] == SysExStart)
     102           1 :             startSysEx(CN); // start a new message
     103             :                             // (overwrite previous unfinished message)
     104           4 :         else if (!receivingSysEx(CN)) { // If we haven't received a SysExStart
     105           2 :             DEBUGFN(F("Error: No SysExStart received"));
     106           2 :             return MIDIReadEvent::NO_MESSAGE; // ignore the data
     107             :         }
     108             :         if (                               // add three data bytes to buffer
     109           6 :             addSysExByte(CN, packet[1]) && //
     110           3 :             addSysExByte(CN, packet[2]) && //
     111           3 :             addSysExByte(CN, SysExEnd)) {
     112           3 :             endSysEx(CN);
     113           3 :             return MIDIReadEvent::SYSEX_MESSAGE;
     114             :         } else {
     115           0 :             return MIDIReadEvent::NO_MESSAGE; // Buffer full, ignore message
     116             :         }
     117             :     }
     118             : #endif // IGNORE_SYSEX
     119             : 
     120           3 :     else if (CIN == MIDICodeIndexNumber::MISC_FUNCTION_CODES) {
     121             :         // Miscellaneous function codes. Reserved for future extensions.
     122             :         // (not implemented)
     123           3 :     } else if (CIN == MIDICodeIndexNumber::CABLE_EVENTS) {
     124             :         // Cable events. Reserved for future expansion.
     125             :         // (not implemented)
     126           3 :     } else if (CIN == MIDICodeIndexNumber::SYSTEM_COMMON_2B) {
     127             :         // Two-byte System Common message
     128             :         // (not implemented)
     129           3 :     } else if (CIN == MIDICodeIndexNumber::SYSTEM_COMMON_3B) {
     130             :         // Three-byte System Common message
     131             :         // (not implemented)
     132           0 :     }
     133             : 
     134             :     // ---------------------- Single byte (real-time) ----------------------- //
     135             : 
     136           3 :     else if (CIN == MIDICodeIndexNumber::SINGLE_BYTE) {
     137             :         // Single Byte
     138           3 :         rtmsg.message = packet[1];
     139           3 :         rtmsg.CN = CN;
     140           3 :         return MIDIReadEvent::REALTIME_MESSAGE;
     141             :     }
     142             : 
     143           0 :     return MIDIReadEvent::NO_MESSAGE;
     144          40 : }
     145             : 
     146             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-6-g40580cd