Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
MIDI_MessageTypes.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <AH/Arduino-Wrapper.h> // Print
4#include <AH/PrintStream/PrintStream.hpp> // operator<<
5#include <AH/STL/cstddef> // size_t
6#include <AH/STL/vector>
7#include <Settings/NamespaceSettings.hpp>
8
9#ifndef ARDUINO
10#include <iostream>
11#endif
12
13#include <Def/Cable.hpp>
14#include <Def/Channel.hpp>
15#include <Def/MIDIAddress.hpp>
16
18
19// -------------------------------------------------------------------------- //
20
22enum class MIDIMessageType : uint8_t {
23 None = 0x00,
25 /* Channel Voice Messages */
26 NoteOff = 0x80,
27 NoteOn = 0x90,
28 KeyPressure = 0xA0,
29 ControlChange = 0xB0,
30 ProgramChange = 0xC0,
31 ChannelPressure = 0xD0,
32 PitchBend = 0xE0,
33
34 SysExStart = 0xF0,
35
36 /* System Common messages */
37 MTCQuarterFrame = 0xF1,
39 SongPositionPointer = 0xF2,
41 SongSelect = 0xF3,
42 UndefinedSysCommon1 = 0xF4,
43 UndefinedSysCommon2 = 0xF5,
44 TuneRequest = 0xF6,
45 SysExEnd = 0xF7,
46
47 /* System Real-Time messages */
48 TimingClock = 0xF8,
49 UndefinedRealTime1 = 0xF9,
50 Start = 0xFA,
51 Continue = 0xFB,
52 Stop = 0xFC,
53 UndefinedRealTime2 = 0xFD,
54 ActiveSensing = 0xFE,
55 SystemReset = 0xFF,
56
57// clang-format off
58#ifndef DOXYGEN
59 NONE CS_DEPREC("Use None instead") = None,
60 NOTE_OFF CS_DEPREC("Use NoteOff instead") = NoteOff,
61 NOTE_ON CS_DEPREC("Use NoteOn instead") = NoteOn,
62 KEY_PRESSURE CS_DEPREC("Use KeyPressure instead") = KeyPressure,
63 CC CS_DEPREC("Use ControlChange instead") = ControlChange,
64 CONTROL_CHANGE CS_DEPREC("Use ControlChange instead") = ControlChange,
65 PROGRAM_CHANGE CS_DEPREC("Use ProgramChange instead") = ProgramChange,
66 CHANNEL_PRESSURE CS_DEPREC("Use ChannelPressure instead") = ChannelPressure,
67 PITCH_BEND CS_DEPREC("Use PitchBend instead") = PitchBend,
68 SYSEX_START CS_DEPREC("Use SysExStart instead") = SysExStart,
69 MTC_QUARTER_FRAME CS_DEPREC("Use MTCQuarterFrame instead") = MTCQuarterFrame,
70 SONG_POSITION_POINTER CS_DEPREC("Use SongPositionPointer instead") = SongPositionPointer,
71 SONG_SELECT CS_DEPREC("Use SongSelect instead") = SongSelect,
72 UNDEFINED_SYSCOMMON_1 CS_DEPREC("Use UndefinedSysCommon1 instead") = UndefinedSysCommon1,
73 UNDEFINED_SYSCOMMON_2 CS_DEPREC("Use UndefinedSysCommon2 instead") = UndefinedSysCommon2,
74 TUNE_REQUEST CS_DEPREC("Use TuneRequest instead") = TuneRequest,
75 SYSEX_END CS_DEPREC("Use SysExEnd instead") = SysExEnd,
76 TIMING_CLOCK CS_DEPREC("Use TimingClock instead") = TimingClock,
77 UNDEFINED_REALTIME_1 CS_DEPREC("Use UndefinedRealTime1 instead") = UndefinedRealTime1,
78 START CS_DEPREC("Use Start instead") = Start,
79 CONTINUE CS_DEPREC("Use Continue instead") = Continue,
80 STOP CS_DEPREC("Use Stop instead") = Stop,
81 UNDEFINED_REALTIME_2 CS_DEPREC("Use UndefinedRealTime2 instead") = UndefinedRealTime2,
82 ACTIVE_SENSING CS_DEPREC("Use ActiveSensing instead") = ActiveSensing,
83 SYSTEM_RESET CS_DEPREC("Use SystemReset instead") = SystemReset,
84#endif // DOXYGEN
85 // clang-format on
86};
87
91enum class MIDICodeIndexNumber : uint8_t {
93 CableEvents = 0x1,
94 SystemCommon2B = 0x2,
95 SystemCommon3B = 0x3,
96 SysExStartCont = 0x4,
97 SystemCommon1B = 0x5,
98 SysExEnd1B = 0x5,
99 SysExEnd2B = 0x6,
100 SysExEnd3B = 0x7,
101
102 NoteOff = 0x8,
103 NoteOn = 0x9,
104 KeyPressure = 0xA,
105 ControlChange = 0xB,
106 ProgramChange = 0xC,
107 ChannelPressure = 0xD,
108 PitchBend = 0xE,
109
110 SingleByte = 0xF,
111};
112
113// -------------------------------------------------------------------------- //
114
117 MIDIMessage(uint8_t header, uint8_t data1, uint8_t data2,
120
125
126 uint8_t header;
127 uint8_t data1;
128 uint8_t data2;
129
131
133 bool operator==(MIDIMessage other) const {
134 return this->header == other.header && this->data1 == other.data1 &&
135 this->data2 == other.data2 && this->cable == other.cable;
136 }
138 bool operator!=(MIDIMessage other) const { return !(*this == other); }
139
143 return static_cast<MIDIMessageType>(header & 0xF0);
144 } else {
145 return static_cast<MIDIMessageType>(header);
146 }
147 }
152 header = static_cast<uint8_t>(type);
153 }
154
156 uint8_t getData1() const { return data1; }
158 uint8_t getData2() const { return data2; }
160 void setData1(uint8_t data) { data1 = data; }
162 void setData2(uint8_t data) { data2 = data; }
163
165 Cable getCable() const { return cable; }
167 void setCable(Cable cable) { this->cable = cable; }
168
171 return header >= (uint8_t(MIDIMessageType::NoteOff) | 0x00) &&
172 header <= (uint8_t(MIDIMessageType::PitchBend) | 0x0F);
173 }
174
181 return (header & 0xF8) == 0xF0 && header != 0xF0;
182 }
183
186 uint16_t getData14bit() const {
187 return data1 | (uint16_t(data2) << uint16_t(7));
188 }
191 void setData14bit(uint16_t data) {
192 data1 = (data >> 0) & 0x7F;
193 data2 = (data >> 7) & 0x7F;
194 }
195
198 void sanitize() {
199 header |= 0x80;
200 data1 &= 0x7F;
201 data2 &= 0x7F;
202 }
203};
204
207
210 uint8_t data2 = 0x00, Cable cable = Cable_1)
211 : MIDIMessage(uint8_t(type) | channel.getRaw(), data1, data2, cable) {}
212
213 explicit ChannelMessage(const MIDIMessage &msg) : MIDIMessage(msg) {}
214
217 return static_cast<MIDIMessageType>(header & 0xF0);
218 }
221 header &= 0x0F;
222 header |= static_cast<uint8_t>(type) & 0xF0;
223 }
224
226 Channel getChannel() const { return Channel(header & 0x0F); }
228 void setChannel(Channel channel) {
229 header &= 0xF0;
230 header |= channel.getRaw();
231 }
232
241
248 bool hasTwoDataBytes() const {
249 auto type = getMessageType();
250 return type <= MIDIMessageType::ControlChange ||
252 }
253
254 constexpr static auto NoteOff = MIDIMessageType::NoteOff;
255 constexpr static auto NoteOn = MIDIMessageType::NoteOn;
260 constexpr static auto PitchBend = MIDIMessageType::PitchBend;
261};
262
265
268 uint8_t data2 = 0x00, Cable cable = Cable_1)
269 : MIDIMessage(type, data1, data2, cable) {}
276
277 explicit SysCommonMessage(const MIDIMessage &msg) : MIDIMessage(msg) {}
278
281 return static_cast<MIDIMessageType>(header);
282 }
283
285 uint8_t getNumberOfDataBytes() const {
287 return 2;
289 return 1;
290 else
291 return 0;
292 }
293
295 constexpr static auto SongPositionPointer =
298 constexpr static auto UndefinedSysCommon1 =
300 constexpr static auto UndefinedSysCommon2 =
303};
304
307 SysExMessage() : data(nullptr), length(0), cable(Cable_1) {}
308
310 SysExMessage(const uint8_t *data, uint16_t length, Cable cable = Cable_1)
311 : data(data), length(length), cable(cable.getRaw()) {}
312
314 SysExMessage(const std::vector<uint8_t> &vec, Cable cable = Cable_1)
315 : SysExMessage(vec.data(), vec.size(), cable) {}
316
318 template <uint16_t N>
319 SysExMessage(const uint8_t (&array)[N], Cable cable = Cable_1)
320 : SysExMessage(array, N, cable) {}
321
322 const uint8_t *data;
323 uint16_t length;
324
326
327 bool operator==(SysExMessage other) const {
328 return this->length == other.length && this->cable == other.cable &&
329 (this->length == 0 ||
330 memcmp(this->data, other.data, length) == 0);
331 }
332 bool operator!=(SysExMessage other) const { return !(*this == other); }
333
335 Cable getCable() const { return cable; }
337 void setCable(Cable cable) { this->cable = cable; }
338
339 bool isFirstChunk() const {
340 return length >= 1 && data[0] == uint8_t(MIDIMessageType::SysExStart);
341 }
342
343 bool isLastChunk() const {
344 return length >= 1 &&
345 data[length - 1] == uint8_t(MIDIMessageType::SysExEnd);
346 }
347
348 bool isCompleteMessage() const { return isFirstChunk() && isLastChunk(); }
349
351 constexpr static auto SysExEnd = MIDIMessageType::SysExEnd;
352};
353
358
362
363 uint8_t message;
365
366 bool operator==(RealTimeMessage other) const {
367 return this->message == other.message && this->cable == other.cable;
368 }
369 bool operator!=(RealTimeMessage other) const { return !(*this == other); }
370
373 message = static_cast<uint8_t>(type);
374 }
377 return static_cast<MIDIMessageType>(message);
378 }
379
381 Cable getCable() const { return cable; }
383 void setCable(Cable cable) { this->cable = cable; }
384
386 bool isValid() const { return message >= 0xF8; }
387
389 constexpr static auto UndefinedRealTime1 =
391 constexpr static auto Start = MIDIMessageType::Start;
392 constexpr static auto Continue = MIDIMessageType::Continue;
393 constexpr static auto Stop = MIDIMessageType::Stop;
394 constexpr static auto UndefinedRealTime2 =
397 constexpr static auto RESET = MIDIMessageType::SystemReset;
398};
399
400#ifndef ARDUINO
401inline std::ostream &operator<<(std::ostream &os, SysExMessage m) {
402 os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length)
403 << " (cable " << m.cable.getOneBased() << ")";
404 return os;
405}
406#endif
407
408inline Print &operator<<(Print &os, SysExMessage m) {
409 os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length)
410 << " (cable " << m.cable.getOneBased() << ")";
411 return os;
412}
413
415inline Print &operator<<(Print &os, MIDIMessageType m) {
416 return os << enum_to_string(m);
417}
418
std::remove_reference< decltype(*F(""))>::type * FlashString_t
constexpr Cable Cable_1
Definition Cable.hpp:118
MIDIMessageType
All possible MIDI status byte values (without channel).
@ UndefinedSysCommon1
Undefined System Common message 0xF4 (1B).
@ Stop
Stop System Real-Time message.
@ KeyPressure
Key Pressure Channel Voice message (3B).
@ TimingClock
Timing Clock System Real-Time message.
@ UndefinedRealTime1
Undefined System Real-Time message 0xF9.
@ NoteOn
Note On Channel Voice message (3B).
@ UndefinedRealTime2
Undefined System Real-Time message 0xFD.
@ ActiveSensing
Active Sensing System Real-Time message.
@ SysExStart
Start of System Exclusive.
@ NoteOff
Note Off Channel Voice message (3B).
@ TuneRequest
Tune Request System Common message (1B).
@ None
Special value that does not correspond to an actual message type.
@ ControlChange
Control Change Channel Voice message (3B).
@ SystemReset
Reset System Real-Time message.
@ MTCQuarterFrame
MIDI Time Code Quarter Frame System Common message (2B).
@ Continue
Continue System Real-Time message.
@ Start
Start System Real-Time message.
@ SongSelect
Song Select System Common message (2B).
@ ChannelPressure
Channel Pressure Channel Voice message (2B).
@ UndefinedSysCommon2
Undefined System Common message 0xF5 (1B).
@ SysExEnd
End of System Exclusive.
@ PitchBend
Pitch Bend Channel Voice message (3B).
@ SongPositionPointer
Song Position Pointer System Common message (3B).
@ ProgramChange
Program Change Channel Voice message (2B).
MIDICodeIndexNumber
MIDI USB Code Index Numbers.
FlashString_t enum_to_string(MIDIMessageType)
Print & operator<<(Print &os, SysExMessage m)
#define CS_DEPREC(...)
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
A type-safe class for MIDI USB Cable numbers.
Definition Cable.hpp:13
constexpr uint8_t getOneBased() const
Get the cable as an integer.
Definition Cable.hpp:36
A type-safe class for MIDI channels.
Definition Channel.hpp:13
constexpr uint8_t getRaw() const
Get the channel as an integer.
Definition Channel.hpp:29
A type-safe utility class for saving a MIDI address consisting of a 7-bit address,...
A class for saving a MIDI channel and cable number.
static constexpr auto NoteOn
void setChannel(Channel channel)
Set the MIDI channel of the message.
MIDIChannelCable getChannelCable() const
Get the MIDI channel and cable number.
void setMessageType(MIDIMessageType type)
Set the MIDI message type.
MIDIAddress getAddress() const
Get the MIDI address of this message, using data1 as the address.
MIDIMessageType getMessageType() const
Get the MIDI message type.
ChannelMessage(const MIDIMessage &msg)
Channel getChannel() const
Get the MIDI channel of the message.
static constexpr auto ProgramChange
ChannelMessage(MIDIMessageType type, Channel channel, uint8_t data1, uint8_t data2=0x00, Cable cable=Cable_1)
Constructor.
static constexpr auto KeyPressure
static constexpr auto NoteOff
bool hasTwoDataBytes() const
Check whether this message has one or two data bytes.
static constexpr auto PitchBend
static constexpr auto ChannelPressure
static constexpr auto ControlChange
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
uint8_t data2
First MIDI data byte.
bool hasValidChannelMessageHeader() const
Check whether the header is a valid header for a channel message.
uint8_t header
MIDI status byte (message type and channel).
void setData1(uint8_t data)
Set the first data byte.
bool operator==(MIDIMessage other) const
Check for equality.
MIDIMessage(MIDIMessageType header, uint8_t data1, uint8_t data2, Cable cable=Cable_1)
Constructor.
void setData2(uint8_t data)
Set the second data byte.
Cable getCable() const
Get the MIDI USB cable number of the message.
void sanitize()
Make sure that the status byte has the most significant bit set and the data bytes have the most sign...
uint8_t getData1() const
Get the first data byte.
uint8_t data1
First MIDI data byte.
void setMessageType(MIDIMessageType type)
Set the MIDI message type.
MIDIMessageType getMessageType() const
Get the MIDI message type.
void setData14bit(uint16_t data)
If Data 1 and Data 2 represent a single 14-bit number, you can use this method to set that number.
Cable cable
USB MIDI cable number;.
uint16_t getData14bit() const
If Data 1 and Data 2 represent a single 14-bit number, you can use this method to retrieve that numbe...
uint8_t getData2() const
Get the second data byte.
bool hasValidSystemCommonHeader() const
Check whether the header is a valid header for a System Common message.
bool operator!=(MIDIMessage other) const
Check for inequality.
MIDIMessage(uint8_t header, uint8_t data1, uint8_t data2, Cable cable=Cable_1)
Constructor.
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
static constexpr auto Start
static constexpr auto UndefinedRealTime1
RealTimeMessage(uint8_t message, Cable cable=Cable_1)
Constructor.
static constexpr auto UndefinedRealTime2
bool isValid() const
Check whether the header is a valid header for a Real-Time message.
bool operator!=(RealTimeMessage other) const
Cable getCable() const
Get the MIDI USB cable number of the message.
static constexpr auto RESET
void setMessageType(MIDIMessageType type)
Set the MIDI message type.
MIDIMessageType getMessageType() const
Get the MIDI message type.
static constexpr auto TimingClock
static constexpr auto Stop
static constexpr auto Continue
RealTimeMessage(MIDIMessageType message, Cable cable=Cable_1)
Constructor.
bool operator==(RealTimeMessage other) const
static constexpr auto ActiveSensing
uint8_t getNumberOfDataBytes() const
Get the number of data bytes of this type of System Common message.
static constexpr auto UndefinedSysCommon1
SysCommonMessage(MIDIMessageType type, uint8_t data1=0x00, uint8_t data2=0x00, Cable cable=Cable_1)
Constructor.
SysCommonMessage(MIDIMessageType type, Cable cable)
Constructor.
static constexpr auto MTCQuarterFrame
SysCommonMessage(const MIDIMessage &msg)
static constexpr auto SongSelect
static constexpr auto UndefinedSysCommon2
MIDIMessageType getMessageType() const
Get the MIDI message type.
static constexpr auto SongPositionPointer
static constexpr auto TuneRequest
SysCommonMessage(MIDIMessageType type, uint8_t data1, Cable cable)
Constructor.
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
SysExMessage()
Constructor.
SysExMessage(const uint8_t(&array)[N], Cable cable=Cable_1)
Constructor.
const uint8_t * data
bool operator!=(SysExMessage other) const
Cable getCable() const
Get the MIDI USB cable number of the message.
bool operator==(SysExMessage other) const
static constexpr auto SysExEnd
SysExMessage(const uint8_t *data, uint16_t length, Cable cable=Cable_1)
Constructor.
bool isCompleteMessage() const
SysExMessage(const std::vector< uint8_t > &vec, Cable cable=Cable_1)
Constructor.
bool isLastChunk() const
bool isFirstChunk() const
static constexpr auto SysExStart