Control Surface master
MIDI Control Surface library for Arduino
MIDI_MessageTypes.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <AH/Arduino-Wrapper.h> // Print
4#include <AH/STL/cstddef> // size_t
5#include <AH/STL/vector>
7#include <Settings/NamespaceSettings.hpp>
8
9#ifndef ARDUINO
10#include <iostream>
11#endif
12
14
15#include <Def/Cable.hpp>
16#include <Def/Channel.hpp>
17#include <Def/MIDIAddress.hpp>
18
20
21// -------------------------------------------------------------------------- //
22
24enum class MIDIMessageType : uint8_t {
25 NONE = 0x00,
26 /* Channel Voice Messages */
27 NOTE_OFF = 0x80, // 3B
28 NOTE_ON = 0x90, // 3B
29 KEY_PRESSURE = 0xA0, // 3B
30 CC = 0xB0, // 3B
31 CONTROL_CHANGE = CC, // 3B
32 PROGRAM_CHANGE = 0xC0, // 2B
33 CHANNEL_PRESSURE = 0xD0, // 2B
34 PITCH_BEND = 0xE0, // 3B
35
36 SYSEX_START = 0xF0,
37
38 /* System Common messages */
39 MTC_QUARTER_FRAME = 0xF1,
41 SONG_SELECT = 0xF3,
44 TUNE_REQUEST = 0xF6,
45 SYSEX_END = 0xF7,
46
47 /* System Real-Time messages */
48 TIMING_CLOCK = 0xF8,
50 START = 0xFA,
51 CONTINUE = 0xFB,
52 STOP = 0xFC,
54 ACTIVE_SENSING = 0xFE,
55 SYSTEM_RESET = 0xFF,
56};
57
61enum class MIDICodeIndexNumber : uint8_t {
63 CABLE_EVENTS = 0x1,
64 SYSTEM_COMMON_2B = 0x2,
65 SYSTEM_COMMON_3B = 0x3,
66 SYSEX_START_CONT = 0x4,
67 SYSTEM_COMMON_1B = 0x5,
68 SYSEX_END_1B = 0x5,
69 SYSEX_END_2B = 0x6,
70 SYSEX_END_3B = 0x7,
71
72 NOTE_OFF = 0x8,
73 NOTE_ON = 0x9,
74 KEY_PRESSURE = 0xA,
75 CONTROL_CHANGE = 0xB,
76 PROGRAM_CHANGE = 0xC,
77 CHANNEL_PRESSURE = 0xD,
78 PITCH_BEND = 0xE,
79
80 SINGLE_BYTE = 0xF,
81};
82
83// -------------------------------------------------------------------------- //
84
87 MIDIMessage(uint8_t header, uint8_t data1, uint8_t data2,
90
94 : header(uint8_t(header)), data1(data1), data2(data2), cable(cable) {}
95
96 uint8_t header;
97 uint8_t data1;
98 uint8_t data2;
99
101
103 bool operator==(MIDIMessage other) const {
104 return this->header == other.header && this->data1 == other.data1 &&
105 this->data2 == other.data2 && this->cable == other.cable;
106 }
108 bool operator!=(MIDIMessage other) const { return !(*this == other); }
109
113 return static_cast<MIDIMessageType>(header & 0xF0);
114 } else {
115 return static_cast<MIDIMessageType>(header);
116 }
117 }
122 header = static_cast<uint8_t>(type);
123 }
124
126 uint8_t getData1() const { return data1; }
128 uint8_t getData2() const { return data2; }
130 void setData1(uint8_t data) { data1 = data; }
132 void setData2(uint8_t data) { data2 = data; }
133
135 Cable getCable() const { return cable; }
137 void setCable(Cable cable) { this->cable = cable; }
138
141 return header >= (uint8_t(MIDIMessageType::NOTE_OFF) | 0x00) &&
142 header <= (uint8_t(MIDIMessageType::PITCH_BEND) | 0x0F);
143 }
144
151 return (header & 0xF8) == 0xF0 && header != 0xF0;
152 }
153
156 uint16_t getData14bit() const {
157 return data1 | (uint16_t(data2) << uint16_t(7));
158 }
161 void setData14bit(uint16_t data) {
162 data1 = (data >> 0) & 0x7F;
163 data2 = (data >> 7) & 0x7F;
164 }
165
168 void sanitize() {
169 header |= 0x80;
170 data1 &= 0x7F;
171 data2 &= 0x7F;
172 }
173};
174
177
180 uint8_t data2 = 0x00, Cable cable = CABLE_1)
181 : MIDIMessage(uint8_t(type) | channel.getRaw(), data1, data2, cable) {}
182
183 explicit ChannelMessage(const MIDIMessage &msg) : MIDIMessage(msg) {}
184
187 return static_cast<MIDIMessageType>(header & 0xF0);
188 }
191 header &= 0x0F;
192 header |= static_cast<uint8_t>(type) & 0xF0;
193 }
194
196 Channel getChannel() const { return Channel(header & 0x0F); }
198 void setChannel(Channel channel) {
199 header &= 0xF0;
200 header |= channel.getRaw();
201 }
202
211
218 bool hasTwoDataBytes() const {
219 auto type = getMessageType();
220 return type <= MIDIMessageType::CONTROL_CHANGE ||
222 }
223
224 constexpr static auto NOTE_OFF = MIDIMessageType::NOTE_OFF;
225 constexpr static auto NOTE_ON = MIDIMessageType::NOTE_ON;
227 constexpr static auto CC = MIDIMessageType::CC;
232};
233
236
239 uint8_t data2 = 0x00, Cable cable = CABLE_1)
240 : MIDIMessage(type, data1, data2, cable) {}
243 : SysCommonMessage(type, data1, 0x00, cable) {}
246 : SysCommonMessage(type, 0x00, 0x00, cable) {}
247
248 explicit SysCommonMessage(const MIDIMessage &msg) : MIDIMessage(msg) {}
249
252 return static_cast<MIDIMessageType>(header);
253 }
254
256 uint8_t getNumberOfDataBytes() const {
258 return 2;
260 return 1;
261 else
262 return 0;
263 }
264
265 constexpr static auto MTC_QUARTER_FRAME =
267 constexpr static auto SONG_POSITION_POINTER =
270 constexpr static auto UNDEFINED_SYSCOMMON_1 =
272 constexpr static auto UNDEFINED_SYSCOMMON_2 =
275};
276
279 SysExMessage() : data(nullptr), length(0), cable(CABLE_1) {}
280
282 SysExMessage(const uint8_t *data, uint16_t length, Cable cable = CABLE_1)
283 : data(data), length(length), cable(cable.getRaw()) {}
284
286 SysExMessage(const std::vector<uint8_t> &vec, Cable cable = CABLE_1)
287 : SysExMessage(vec.data(), vec.size(), cable) {}
288
290 template <uint16_t N>
291 SysExMessage(const uint8_t (&array)[N], Cable cable = CABLE_1)
292 : SysExMessage(array, N, cable) {}
293
294 const uint8_t *data;
295 uint16_t length;
296
298
299 bool operator==(SysExMessage other) const {
300 return this->length == other.length && this->cable == other.cable &&
301 (this->length == 0 ||
302 memcmp(this->data, other.data, length) == 0);
303 }
304 bool operator!=(SysExMessage other) const { return !(*this == other); }
305
307 Cable getCable() const { return cable; }
309 void setCable(Cable cable) { this->cable = cable; }
310
311 bool isFirstChunk() const {
312 return length >= 1 && data[0] == uint8_t(MIDIMessageType::SYSEX_START);
313 }
314
315 bool isLastChunk() const {
316 return length >= 1 &&
317 data[length - 1] == uint8_t(MIDIMessageType::SYSEX_END);
318 }
319
320 bool isCompleteMessage() const { return isFirstChunk() && isLastChunk(); }
321
323 constexpr static auto SYSEX_END = MIDIMessageType::SYSEX_END;
324};
325
329 : message(message), cable(cable.getRaw()) {}
330
333 : message(uint8_t(message)), cable(cable.getRaw()) {}
334
335 uint8_t message;
337
338 bool operator==(RealTimeMessage other) const {
339 return this->message == other.message && this->cable == other.cable;
340 }
341 bool operator!=(RealTimeMessage other) const { return !(*this == other); }
342
345 message = static_cast<uint8_t>(type);
346 }
349 return static_cast<MIDIMessageType>(message);
350 }
351
353 Cable getCable() const { return cable; }
355 void setCable(Cable cable) { this->cable = cable; }
356
358 bool isValid() const { return message >= 0xF8; }
359
361 constexpr static auto UNDEFINED_REALTIME_1 =
363 constexpr static auto START = MIDIMessageType::START;
364 constexpr static auto CONTINUE = MIDIMessageType::CONTINUE;
365 constexpr static auto STOP = MIDIMessageType::STOP;
366 constexpr static auto UNDEFINED_REALTIME_2 =
369 constexpr static auto RESET = MIDIMessageType::SYSTEM_RESET;
370};
371
372#ifndef ARDUINO
373inline std::ostream &operator<<(std::ostream &os, SysExMessage m) {
374 os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length)
375 << " (cable " << m.cable.getOneBased() << ")";
376 return os;
377}
378#endif
379
380inline Print &operator<<(Print &os, SysExMessage m) {
381 os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length)
382 << " (cable " << m.cable.getOneBased() << ")";
383 return os;
384}
385
387inline Print &operator<<(Print &os, MIDIMessageType m) {
388 return os << enum_to_string(m);
389}
390
392
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).
MIDICodeIndexNumber
MIDI USB Code Index Numbers.
FlashString_t enum_to_string(MIDIMessageType)
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
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.
Definition: MIDIAddress.hpp:24
Print & operator<<(Print &os, Quaternion e)
Printing.
Definition: Quaternion.cpp:28
constexpr static auto PROGRAM_CHANGE
constexpr static auto CONTROL_CHANGE
constexpr static auto CC
constexpr static auto NOTE_OFF
void setChannel(Channel channel)
Set the MIDI channel of the message.
MIDIChannelCable getChannelCable() const
Get the MIDI channel and cable number.
constexpr static auto KEY_PRESSURE
ChannelMessage(MIDIMessageType type, Channel channel, uint8_t data1, uint8_t data2=0x00, Cable cable=CABLE_1)
Constructor.
void setMessageType(MIDIMessageType type)
Set the MIDI message type.
MIDIAddress getAddress() const
Get the MIDI address of this message, using data1 as the address.
constexpr static auto CHANNEL_PRESSURE
MIDIMessageType getMessageType() const
Get the MIDI message type.
ChannelMessage(const MIDIMessage &msg)
constexpr static auto PITCH_BEND
Channel getChannel() const
Get the MIDI channel of the message.
constexpr static auto NOTE_ON
bool hasTwoDataBytes() const
Check whether this message has one or two data bytes.
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
uint8_t data2
First MIDI data byte.
MIDIMessage(uint8_t header, uint8_t data1, uint8_t data2, Cable cable=CABLE_1)
Constructor.
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.
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.
MIDIMessage(MIDIMessageType header, uint8_t data1, uint8_t data2, Cable cable=CABLE_1)
Constructor.
bool operator!=(MIDIMessage other) const
Check for inequality.
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
RealTimeMessage(uint8_t message, Cable cable=CABLE_1)
Constructor.
RealTimeMessage(MIDIMessageType message, Cable cable=CABLE_1)
Constructor.
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.
constexpr static auto RESET
constexpr static auto UNDEFINED_REALTIME_2
void setMessageType(MIDIMessageType type)
Set the MIDI message type.
constexpr static auto TIMING_CLOCK
MIDIMessageType getMessageType() const
Get the MIDI message type.
constexpr static auto UNDEFINED_REALTIME_1
constexpr static auto START
constexpr static auto ACTIVE_SENSING
constexpr static auto CONTINUE
bool operator==(RealTimeMessage other) const
constexpr static auto STOP
SysCommonMessage(MIDIMessageType type, uint8_t data1=0x00, uint8_t data2=0x00, Cable cable=CABLE_1)
Constructor.
uint8_t getNumberOfDataBytes() const
Get the number of data bytes of this type of System Common message.
constexpr static auto SONG_POSITION_POINTER
constexpr static auto TUNE_REQUEST
constexpr static auto UNDEFINED_SYSCOMMON_1
constexpr static auto MTC_QUARTER_FRAME
SysCommonMessage(MIDIMessageType type, Cable cable)
Constructor.
SysCommonMessage(const MIDIMessage &msg)
constexpr static auto SONG_SELECT
MIDIMessageType getMessageType() const
Get the MIDI message type.
constexpr static auto UNDEFINED_SYSCOMMON_2
SysCommonMessage(MIDIMessageType type, uint8_t data1, Cable cable)
Constructor.
void setCable(Cable cable)
Set the MIDI USB cable number of the message.
SysExMessage(const uint8_t(&array)[N], Cable cable=CABLE_1)
Constructor.
SysExMessage()
Constructor.
constexpr static auto SYSEX_START
SysExMessage(const uint8_t *data, uint16_t length, Cable cable=CABLE_1)
Constructor.
SysExMessage(const std::vector< uint8_t > &vec, 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
bool isCompleteMessage() const
bool isLastChunk() const
bool isFirstChunk() const
constexpr static auto SYSEX_END