Control Surface  1.2.0
MIDI Control Surface library for Arduino
SerialMIDI_Parser.cpp
Go to the documentation of this file.
1 #include "SerialMIDI_Parser.hpp"
2 
4 
6  DEBUGFN(hex << NAMEDVALUE(midiByte) << dec);
7 #if !IGNORE_SYSEX
8  // SysEx constants
9  constexpr uint8_t SysExStart =
10  static_cast<uint8_t>(MIDIMessageType::SYSEX_START);
11  constexpr uint8_t SysExEnd =
12  static_cast<uint8_t>(MIDIMessageType::SYSEX_END);
13 
14  // If the previous byte was a SysExStart
15  // I have to handle a start in the next time step, because a start can also
16  // end the previous message. When that happens, I have to return
17  // SYSEX_MESSAGE without resetting the buffer.
18  // Then, after handling the message by the user, I do have to reset the
19  // buffer.
20  if (midimsg.header == SysExStart && !sysexbuffer.isReceiving()) {
21  startSysEx();
22  addSysExByte(SysExStart);
23  }
24 #endif
25 
26  // If it's a status byte (first byte of a message)
27  if (isStatus(midiByte)) {
28  // If it's a Real-Time message
29  if (midiByte >= uint8_t(MIDIMessageType::TIMING_CLOCK)) {
30  rtmsg.message = midiByte;
32  }
33  // Normal header (channel message, system exclusive, system common)
34  else {
35  // If a SysEx message was being received, and now we receive
36  // another status byte, remember to correctly terminate the SysEx
37  // message later
38  bool unterminatedSysEx = midimsg.header == SysExStart;
39 
40  // Save the newly received status byte
41  midimsg.header = midiByte;
42  // A new message starts, so we haven't received the second byte yet
43  thirdByte = false;
44 
45  if (midimsg.header == uint8_t(MIDIMessageType::TUNE_REQUEST)) {
46  // Tune request (not implemented)
47  // TODO: should I implement this as a Real-Time message?
48  // (That might lead to problems when a SysEx message is
49  // terminated by a Tune Request, see unterminatedSysEx below)
50  // TODO: should I set midimsg.header in this case?
51  }
52 
53 #if !IGNORE_SYSEX
54  if (unterminatedSysEx) {
55  // If we're currently receiving a SysEx message
56  addSysExByte(SysExEnd); // Try to add SysExEnd byte to buffer
57  // Even if the buffer is full, end the message anyway
58  endSysEx();
59  return MIDIReadEvent::SYSEX_MESSAGE;
60  }
61 #else
62  (void)unterminatedSysEx;
63 #endif // IGNORE_SYSEX
64  }
65  }
66 
67  // If it's a data byte
68  else {
69  if (midimsg.header == 0) {
70  DEBUGFN("Warning: No header");
71  ; // Ignore
72  }
73  // Third byte of three (data 2)
74  else if (thirdByte) {
75  midimsg.data2 = midiByte;
76  thirdByte = false;
77  return MIDIReadEvent::CHANNEL_MESSAGE;
78  }
79  // Second byte (data 1) or SysEx data
80  else {
81  // Channel message with two data bytes
82  if (midimsg.hasTwoDataBytes()) {
83  midimsg.data1 = midiByte;
84  thirdByte = true; // expect a third byte next
85  }
86  // Channel message with one data byte
87  else if (midimsg.hasValidHeader()) {
88  midimsg.data1 = midiByte;
89  return MIDIReadEvent::CHANNEL_MESSAGE;
90  }
91  // Not a channel message
92 #if !IGNORE_SYSEX
93  // SysEx data byte
94  else if (midimsg.header == SysExStart) {
95  addSysExByte(midiByte);
96  }
97 #endif // IGNORE_SYSEX
98  else {
99  DEBUGFN("Data byte ignored");
100  }
101  }
102  }
103  return MIDIReadEvent::NO_MESSAGE;
104 }
105 
SerialMIDI_Parser::startSysEx
void startSysEx()
Definition: SerialMIDI_Parser.hpp:23
SerialMIDI_Parser::addSysExByte
bool addSysExByte(uint8_t data)
Definition: SerialMIDI_Parser.hpp:22
ChannelMessage::hasValidHeader
bool hasValidHeader() const
Check whether the header is a valid header for a channel message.
Definition: MIDI_MessageTypes.hpp:131
NAMEDVALUE
#define NAMEDVALUE(x)
Macro for printing an expression as a string, followed by its value.
Definition: Debug.hpp:69
SysExBuffer::isReceiving
bool isReceiving() const
Check if the buffer is receiving a SysEx message.
Definition: SysExBuffer.cpp:31
SerialMIDI_Parser::sysexbuffer
SysExBuffer sysexbuffer
Definition: SerialMIDI_Parser.hpp:20
AH::dec
Print & dec(Print &printer)
Definition: PrintStream.cpp:77
BEGIN_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:9
ChannelMessage::header
uint8_t header
MIDI status byte (message type and channel).
Definition: MIDI_MessageTypes.hpp:83
ChannelMessage::data2
uint8_t data2
First MIDI data byte.
Definition: MIDI_MessageTypes.hpp:85
MIDI_Parser::rtmsg
RealTimeMessage rtmsg
Definition: MIDI_Parser.hpp:41
END_CS_NAMESPACE
#define END_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:10
SerialMIDI_Parser::endSysEx
void endSysEx()
Definition: SerialMIDI_Parser.hpp:24
ChannelMessage::hasTwoDataBytes
bool hasTwoDataBytes() const
Check whether this message has one or two data bytes.
Definition: MIDI_MessageTypes.hpp:124
MIDIReadEvent::NO_MESSAGE
@ NO_MESSAGE
No new incoming methods.
AH::hex
Print & hex(Print &printer)
Definition: PrintStream.cpp:62
MIDI_Parser::midimsg
ChannelMessage midimsg
Definition: MIDI_Parser.hpp:40
ChannelMessage::data1
uint8_t data1
First MIDI data byte.
Definition: MIDI_MessageTypes.hpp:84
MIDI_Parser::isStatus
static bool isStatus(uint8_t data)
Check if the given byte is a MIDI header byte.
Definition: MIDI_Parser.hpp:45
DEBUGFN
#define DEBUGFN(x)
Print an expression and its function (function name and line number) to the debug output if debugging...
Definition: Debug.hpp:93
SerialMIDI_Parser::parse
MIDIReadEvent parse(uint8_t midibyte)
Definition: SerialMIDI_Parser.cpp:5
MIDIReadEvent
MIDIReadEvent
Result of the MIDI interface read methods.
Definition: MIDI_Parser.hpp:15
RealTimeMessage::message
uint8_t message
Definition: MIDI_MessageTypes.hpp:189
SerialMIDI_Parser.hpp
SerialMIDI_Parser::thirdByte
bool thirdByte
Definition: SerialMIDI_Parser.hpp:28