Control Surface
main
MIDI Control Surface library for Arduino
Toggle main menu visibility
Loading...
Searching...
No Matches
src
MIDI_Parsers
USBMIDI_Parser.cpp
Go to the documentation of this file.
1
#include "
USBMIDI_Parser.hpp
"
2
#include <
Settings/SettingsWrapper.hpp
>
3
4
BEGIN_CS_NAMESPACE
5
6
MIDIReadEvent
USBMIDI_Parser::handleChannelMessage
(
MIDIUSBPacket_t
packet,
7
Cable
cable) {
8
midimsg
.header = packet[1];
9
midimsg
.data1 = packet[2];
10
midimsg
.data2 = packet[3];
11
midimsg
.cable = cable;
12
return
MIDIReadEvent::CHANNEL_MESSAGE
;
13
}
14
15
MIDIReadEvent
USBMIDI_Parser::handleSysExStartCont
(
MIDIUSBPacket_t
packet,
16
Cable
cable) {
17
#if !IGNORE_SYSEX
18
// If this is a SysEx start packet
19
if
(packet[1] == uint8_t(
MIDIMessageType::SysExStart
)) {
20
startSysEx
(cable);
// start a new message
21
// (overwrites previous unfinished message)
22
}
23
// If we haven't received a SysExStart
24
else
if
(!
receivingSysEx
(cable)) {
25
DEBUGREF
(F(
"No SysExStart received"
));
26
return
MIDIReadEvent::NO_MESSAGE
;
// ignore the data
27
}
28
29
// Check if the SysEx buffer has enough space to store the data
30
if
(!
hasSysExSpace
(cable, 3)) {
31
storePacket
(packet);
32
endSysExChunk
(cable);
33
return
MIDIReadEvent::SYSEX_CHUNK
;
34
}
35
36
// Enough space available in buffer, store the data
37
addSysExBytes
(cable, &packet[1], 3);
38
#else
39
(void)packet;
40
(void)cable;
41
#endif
42
return
MIDIReadEvent::NO_MESSAGE
;
// SysEx is not finished yet
43
}
44
45
template
<u
int
8_t NumBytes>
46
MIDIReadEvent
USBMIDI_Parser::handleSysExEnd
(
MIDIUSBPacket_t
packet,
47
Cable
cable) {
48
static_assert
(NumBytes == 2 || NumBytes == 3,
49
"Only 2- or 3-byte SysEx packets are supported"
);
50
51
#if !IGNORE_SYSEX
52
// This could be the a very short SysEx message that starts and ends with
53
// this packet
54
if
(packet[1] == uint8_t(
MIDIMessageType::SysExStart
)) {
55
startSysEx
(cable);
// start a new message
56
// (overwrites previous unfinished message)
57
}
58
// If we haven't received a SysExStart
59
else
if
(!
receivingSysEx
(cable)) {
60
DEBUGFN
(F(
"No SysExStart received"
));
61
return
MIDIReadEvent::NO_MESSAGE
;
// ignore the data
62
}
63
64
// Check if the SysEx buffer has enough space to store the end byte
65
if
(!
hasSysExSpace
(cable, NumBytes)) {
66
storePacket
(packet);
67
endSysExChunk
(cable);
68
return
MIDIReadEvent::SYSEX_CHUNK
;
// Buffer full
69
}
70
71
// Enough space available in buffer, finish the message
72
addSysExBytes
(cable, &packet[1], NumBytes);
73
endSysEx
(cable);
74
return
MIDIReadEvent::SYSEX_MESSAGE
;
75
#else
76
(void)packet;
77
(void)cable;
78
return
MIDIReadEvent::NO_MESSAGE
;
79
#endif
80
}
81
82
template
<>
83
MIDIReadEvent
USBMIDI_Parser::handleSysExEnd<1>
(
MIDIUSBPacket_t
packet,
84
Cable
cable) {
85
// Single-byte System Common Message
86
if
(packet[1] != uint8_t(
MIDIMessageType::SysExEnd
)) {
87
// System Common (1 byte)
88
midimsg
.header = packet[1];
89
midimsg
.cable = cable;
90
return
MIDIReadEvent::SYSCOMMON_MESSAGE
;
91
}
92
93
#if !IGNORE_SYSEX
94
// SysEx ends with following single byte
95
else
{
96
// If we haven't received a SysExStart
97
if
(!
receivingSysEx
(cable)) {
98
DEBUGREF
(F(
"No SysExStart received"
));
99
return
MIDIReadEvent::NO_MESSAGE
;
// ignore the data
100
}
101
102
// Check if the SysEx buffer has enough space to store the end byte
103
if
(!
hasSysExSpace
(cable, 1)) {
104
storePacket
(packet);
105
endSysExChunk
(cable);
106
return
MIDIReadEvent::SYSEX_CHUNK
;
107
}
108
109
// Enough space available in buffer, finish the message
110
addSysExByte
(cable, packet[1]);
111
endSysEx
(cable);
112
return
MIDIReadEvent::SYSEX_MESSAGE
;
113
}
114
#else
115
(void)packet;
116
(void)cable;
117
return
MIDIReadEvent::NO_MESSAGE
;
118
#endif
119
}
120
121
MIDIReadEvent
USBMIDI_Parser::handleSysCommon
(
MIDIUSBPacket_t
packet,
122
Cable
cable) {
123
midimsg
.header = packet[1];
124
midimsg
.data1 = packet[2];
125
midimsg
.data2 = packet[3];
126
midimsg
.cable = cable;
127
return
MIDIReadEvent::SYSCOMMON_MESSAGE
;
128
}
129
130
// Single Byte
131
MIDIReadEvent
USBMIDI_Parser::handleSingleByte
(
MIDIUSBPacket_t
packet,
132
Cable
cable) {
133
rtmsg
.message = packet[1];
134
rtmsg
.cable = cable;
135
return
MIDIReadEvent::REALTIME_MESSAGE
;
136
}
137
138
// https://usb.org/sites/default/files/midi10.pdf
139
MIDIReadEvent
USBMIDI_Parser::feed
(
MIDIUSBPacket_t
packet) {
140
// DEBUG("MIDIUSB packet:\t" << hex << packet[0] << ' ' << packet[1] << ' '
141
// << packet[2] << ' ' << packet[3] << dec);
142
143
// MIDI USB cable number and code index number
144
Cable
cable =
Cable
(packet[0] >> 4);
145
MIDICodeIndexNumber
CIN =
MIDICodeIndexNumber
(packet[0] & 0xF);
146
147
// Ignore all messages for cables that we don't have
148
if
(cable.
getRaw
() >=
USB_MIDI_NUMBER_OF_CABLES
)
149
return
MIDIReadEvent::NO_MESSAGE
;
// LCOV_EXCL_LINE
150
151
using
M =
MIDICodeIndexNumber
;
152
switch
(CIN) {
153
case
M::MiscFunctionCodes:
break
;
// LCOV_EXCL_LINE
154
case
M::CableEvents:
break
;
// LCOV_EXCL_LINE
155
case
M::SystemCommon2B:
// fallthrough
156
case
M::SystemCommon3B:
return
handleSysCommon
(packet, cable);
157
case
M::SysExStartCont:
return
handleSysExStartCont
(packet, cable);
158
case
M::SysExEnd1B:
return
handleSysExEnd<1>
(packet, cable);
159
case
M::SysExEnd2B:
return
handleSysExEnd<2>
(packet, cable);
160
case
M::SysExEnd3B:
return
handleSysExEnd<3>
(packet, cable);
161
case
M::NoteOff:
// fallthrough
162
case
M::NoteOn:
// fallthrough
163
case
M::KeyPressure:
// fallthrough
164
case
M::ControlChange:
// fallthrough
165
case
M::ProgramChange:
// fallthrough
166
case
M::ChannelPressure:
// fallthrough
167
case
M::PitchBend:
return
handleChannelMessage
(packet, cable);
168
case
M::SingleByte:
return
handleSingleByte
(packet, cable);
169
default
:
break
;
// LCOV_EXCL_LINE
170
}
171
172
return
MIDIReadEvent::NO_MESSAGE
;
// LCOV_EXCL_LINE
173
}
174
175
MIDIReadEvent
USBMIDI_Parser::resume
() {
176
#if !IGNORE_SYSEX
177
if
(!
hasStoredPacket
())
178
return
MIDIReadEvent::NO_MESSAGE
;
179
180
MIDIUSBPacket_t
packet =
popStoredPacket
();
181
182
// If a SysEx message was in progress
183
if
(
receivingSysEx
(
activeCable
)) {
184
// Reset the buffer for the next chunk
185
startSysEx
(
activeCable
);
186
}
187
188
return
feed
(packet);
189
#else
190
return
MIDIReadEvent::NO_MESSAGE
;
191
#endif
192
}
193
194
END_CS_NAMESPACE
MIDIReadEvent
MIDIReadEvent
Values returned by the MIDI reading functions.
Definition
MIDIReadEvent.hpp:11
MIDIReadEvent::CHANNEL_MESSAGE
@ CHANNEL_MESSAGE
A MIDI Channel message was received.
Definition
MIDIReadEvent.hpp:13
MIDIReadEvent::SYSEX_CHUNK
@ SYSEX_CHUNK
An incomplete System Exclusive message.
Definition
MIDIReadEvent.hpp:16
MIDIReadEvent::SYSCOMMON_MESSAGE
@ SYSCOMMON_MESSAGE
A MIDI System Common message was received.
Definition
MIDIReadEvent.hpp:17
MIDIReadEvent::NO_MESSAGE
@ NO_MESSAGE
No new messages were received.
Definition
MIDIReadEvent.hpp:12
MIDIReadEvent::SYSEX_MESSAGE
@ SYSEX_MESSAGE
A MIDI System Exclusive message was received.
Definition
MIDIReadEvent.hpp:14
MIDIReadEvent::REALTIME_MESSAGE
@ REALTIME_MESSAGE
A MIDI Real-Time message was received.
Definition
MIDIReadEvent.hpp:15
MIDIMessageType::SysExStart
@ SysExStart
Start of System Exclusive.
Definition
MIDI_MessageTypes.hpp:34
MIDIMessageType::SysExEnd
@ SysExEnd
End of System Exclusive.
Definition
MIDI_MessageTypes.hpp:45
MIDICodeIndexNumber
MIDICodeIndexNumber
MIDI USB Code Index Numbers.
Definition
MIDI_MessageTypes.hpp:91
END_CS_NAMESPACE
#define END_CS_NAMESPACE
Definition
Settings/NamespaceSettings.hpp:14
BEGIN_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Definition
Settings/NamespaceSettings.hpp:11
SettingsWrapper.hpp
USBMIDI_Parser.hpp
USB_MIDI_NUMBER_OF_CABLES
#define USB_MIDI_NUMBER_OF_CABLES
Definition
USBMIDI_Parser.hpp:16
Cable
A type-safe class for MIDI USB Cable numbers.
Definition
Cable.hpp:13
Cable::getRaw
constexpr uint8_t getRaw() const
Get the cable as an integer.
Definition
Cable.hpp:29
MIDI_Parser::midimsg
MIDIMessage midimsg
Definition
MIDI_Parser.hpp:32
MIDI_Parser::rtmsg
RealTimeMessage rtmsg
Definition
MIDI_Parser.hpp:33
USBMIDI_Parser::hasSysExSpace
bool hasSysExSpace(Cable cable, uint8_t amount) const
Definition
USBMIDI_Parser.hpp:77
USBMIDI_Parser::handleSingleByte
MIDIReadEvent handleSingleByte(MIDIUSBPacket_t packet, Cable cable)
Definition
USBMIDI_Parser.cpp:131
USBMIDI_Parser::resume
MIDIReadEvent resume()
Resume the parser with the previously stored and unhandled packet.
Definition
USBMIDI_Parser.cpp:175
USBMIDI_Parser::handleSysExStartCont
MIDIReadEvent handleSysExStartCont(MIDIUSBPacket_t packet, Cable cable)
Definition
USBMIDI_Parser.cpp:15
USBMIDI_Parser::endSysExChunk
void endSysExChunk(Cable cable)
Definition
USBMIDI_Parser.hpp:76
USBMIDI_Parser::storePacket
void storePacket(MIDIUSBPacket_t packet)
Definition
USBMIDI_Parser.hpp:90
USBMIDI_Parser::handleSysExEnd
MIDIReadEvent handleSysExEnd(MIDIUSBPacket_t packet, Cable cable)
Definition
USBMIDI_Parser.cpp:46
USBMIDI_Parser::handleChannelMessage
MIDIReadEvent handleChannelMessage(MIDIUSBPacket_t packet, Cable cable)
Definition
USBMIDI_Parser.cpp:6
USBMIDI_Parser::startSysEx
void startSysEx(Cable cable)
Definition
USBMIDI_Parser.hpp:71
USBMIDI_Parser::receivingSysEx
bool receivingSysEx(Cable cable) const
Definition
USBMIDI_Parser.hpp:86
USBMIDI_Parser::hasStoredPacket
bool hasStoredPacket() const
Definition
USBMIDI_Parser.hpp:91
USBMIDI_Parser::popStoredPacket
MIDIUSBPacket_t popStoredPacket()
Definition
USBMIDI_Parser.hpp:92
USBMIDI_Parser::feed
MIDIReadEvent feed(MIDIUSBPacket_t packet)
Feed a new packet to the parser.
Definition
USBMIDI_Parser.cpp:139
USBMIDI_Parser::addSysExByte
void addSysExByte(Cable cable, uint8_t data)
Definition
USBMIDI_Parser.hpp:80
USBMIDI_Parser::activeCable
Cable activeCable
Definition
USBMIDI_Parser.hpp:98
USBMIDI_Parser::endSysEx
void endSysEx(Cable cable)
Definition
USBMIDI_Parser.hpp:72
USBMIDI_Parser::addSysExBytes
void addSysExBytes(Cable cable, const uint8_t *data, uint8_t len)
Definition
USBMIDI_Parser.hpp:83
USBMIDI_Parser::handleSysCommon
MIDIReadEvent handleSysCommon(MIDIUSBPacket_t packet, Cable cable)
Definition
USBMIDI_Parser.cpp:121
USBMIDI_Parser::MIDIUSBPacket_t
AH::Array< uint8_t, 4 > MIDIUSBPacket_t
Definition
USBMIDI_Parser.hpp:30
DEBUGFN
#define DEBUGFN(x)
Print an expression and its function (function name and line number) to the debug output if debugging...
Definition
Debug.hpp:115
DEBUGREF
#define DEBUGREF(x)
Print an expression and its location (file and line number) to the debug output if debugging is enabl...
Definition
Debug.hpp:105
Generated by
1.17.0