-
Notifications
You must be signed in to change notification settings - Fork 28
/
midi_message.hh
121 lines (101 loc) · 2.87 KB
/
midi_message.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#pragma once
#include <array>
#include <cstdint>
#include <cstdio>
// Specifications from
// https://www.midi.org/specifications/midi1-specifications/m1-v4-2-1-midi-1-0-detailed-specification-96-1-4
enum MidiCommand : uint8_t {
NoteOff = 0x8,
NoteOn = 0x9,
PolyKeyPressue = 0xA,
ControlChange = 0xB,
ProgramChange = 0xC,
ChannelPressure = 0xD,
PitchBend = 0xE,
Sys = 0xF,
};
struct MidiStatusByte {
MidiCommand command : 4;
uint8_t channel : 4;
static MidiStatusByte make(uint8_t raw)
{
return MidiStatusByte{
.command = MidiCommand(raw >> 4),
.channel = uint8_t(raw & 0x0F),
};
}
operator uint8_t() const { return (uint8_t)command << 4 | channel; }
};
struct MidiDataBytes {
uint8_t byte[2];
operator uint16_t() const { return ((uint16_t)byte[0] << 8) | byte[1]; }
};
enum MidiSystemCommonCommand : uint8_t {
TimeCodeQuarterFrame = 0xF1,
SongPositionPtr = 0xF2,
SongSelect = 0xF3,
TuneRequest = 0xF6,
EndExclusive = 0xF7,
};
enum MidiSystemRealTimeCommand : uint8_t {
TimingClock = 0xF8,
Start = 0xFA,
Continue = 0xFB,
Stop = 0xFC,
ActiveSending = 0xFE,
SystemReset = 0xFF,
};
enum MidiSystemExclusiveCommand : uint8_t {
SysEx = 0xF0,
};
struct MidiMessage {
MidiStatusByte status;
MidiDataBytes data;
MidiMessage() = default;
MidiMessage(uint8_t status_byte, uint8_t data_byte0 = 0, uint8_t data_byte1 = 0)
: status{MidiStatusByte::make(status_byte)}
, data{data_byte0, data_byte1}
{}
template<MidiCommand cmd>
bool is_command() const
{
return (status.command == cmd);
}
template<MidiSystemCommonCommand cmd>
bool is_system_common() const
{
return status == cmd;
}
template<MidiSystemRealTimeCommand cmd>
bool is_system_realtime() const
{
return status == cmd;
}
bool is_sysex() const { return status == SysEx; }
uint32_t raw() const { return (status << 16) | data; }
static void print(MidiMessage msg)
{
if (msg.is_command<NoteOn>()) {
printf("Note: %d Vel: %d\n", msg.data.byte[0], msg.data.byte[1]);
} else if (msg.is_command<NoteOff>()) {
printf("Note: %d OFF\n", msg.data.byte[0]);
} else if (msg.is_command<PolyKeyPressue>()) {
printf("Poly Key Pressure: %d %d\n", msg.data.byte[0], msg.data.byte[1]);
} else if (msg.is_command<ControlChange>()) {
printf("CC: #%d = %d\n", msg.data.byte[0], msg.data.byte[1]);
} else if (msg.is_command<ProgramChange>()) {
printf("PC: #%d\n", msg.data.byte[0]);
} else if (msg.is_command<ChannelPressure>()) {
printf("CP: #%d\n", msg.data.byte[0]);
} else if (msg.is_command<ChannelPressure>()) {
printf("Bend: #%d\n", (msg.data.byte[0] | (msg.data.byte[1] << 7)) - 8192);
} else if (msg.is_system_realtime<TimingClock>()) {
// printf("Clk\n");
} else if (msg.is_sysex()) {
printf("SYSEX: 0x%02x%02x\n", msg.data.byte[0], msg.data.byte[1]);
} else if (msg.raw()) {
printf("Raw: %06x\n", msg.raw());
}
}
void print() const { MidiMessage::print(*this); }
};