Control Surface master
MIDI Control Surface library for Arduino
MIDI_Callbacks.hpp
Go to the documentation of this file.
1#pragma once
2
5
7
9
10// LCOV_EXCL_START
11
16 public:
26
28 virtual ~MIDI_Callbacks() = default;
29};
30
31// LCOV_EXCL_STOP
32
33template <class Derived>
35 protected:
39 // clang-format off
40 void onNoteOff(Channel channel, uint8_t note, uint8_t velocity, Cable cable);
41 void onNoteOn(Channel channel, uint8_t note, uint8_t velocity, Cable cable);
42 void onKeyPressure(Channel channel, uint8_t note, uint8_t pressure, Cable cable);
43 void onControlChange(Channel channel, uint8_t controller, uint8_t value, Cable cable);
44 void onProgramChange(Channel channel, uint8_t program, Cable cable);
45 void onChannelPressure(Channel channel, uint8_t pressure, Cable cable);
46 void onPitchBend(Channel channel, uint16_t bend, Cable cable);
47 void onSystemExclusive(SysExMessage message);
48 void onTimeCodeQuarterFrame(uint8_t data, Cable cable);
49 void onSongPosition(uint16_t beats, Cable cable);
50 void onSongSelect(uint8_t songnumber, Cable cable);
51 void onTuneRequest(Cable cable);
52 void onClock(Cable cable);
53 void onStart(Cable cable);
54 void onContinue(Cable cable);
55 void onStop(Cable cable);
56 void onActiveSensing(Cable cable);
57 void onSystemReset(Cable cable);
58 // clang-format on
60
62 using MMT = MIDIMessageType;
63 switch (msg.getMessageType()) {
64 case MMT::NONE: break;
65 case MMT::NOTE_OFF:
66 CRTP(Derived).onNoteOff(msg.getChannel(), msg.getData1(),
67 msg.getData2(), msg.getCable());
68 break;
69 case MMT::NOTE_ON:
70 CRTP(Derived).onNoteOn(msg.getChannel(), msg.getData1(),
71 msg.getData2(), msg.getCable());
72 break;
73 case MMT::KEY_PRESSURE:
74 CRTP(Derived).onKeyPressure(msg.getChannel(), msg.getData1(),
75 msg.getData2(), msg.getCable());
76 break;
77 case MMT::CONTROL_CHANGE:
78 CRTP(Derived).onControlChange(msg.getChannel(), msg.getData1(),
79 msg.getData2(), msg.getCable());
80 break;
81 case MMT::PROGRAM_CHANGE:
82 CRTP(Derived).onProgramChange(msg.getChannel(), msg.getData1(),
83 msg.getCable());
84 break;
85 case MMT::CHANNEL_PRESSURE:
86 CRTP(Derived).onChannelPressure(msg.getChannel(),
87 msg.getData1(), msg.getCable());
88 break;
89 case MMT::PITCH_BEND:
90 CRTP(Derived).onPitchBend(msg.getChannel(), msg.getData14bit(),
91 msg.getCable());
92 break;
93 case MMT::SYSEX_START:
94 case MMT::MTC_QUARTER_FRAME:
95 case MMT::SONG_POSITION_POINTER:
96 case MMT::SONG_SELECT:
97 case MMT::UNDEFINED_SYSCOMMON_1:
98 case MMT::UNDEFINED_SYSCOMMON_2:
99 case MMT::TUNE_REQUEST:
100 case MMT::SYSEX_END:
101 case MMT::TIMING_CLOCK:
102 case MMT::UNDEFINED_REALTIME_1:
103 case MMT::START:
104 case MMT::CONTINUE:
105 case MMT::STOP:
106 case MMT::UNDEFINED_REALTIME_2:
107 case MMT::ACTIVE_SENSING:
108 case MMT::SYSTEM_RESET:
109 default: break;
110 }
111 }
112
114 CRTP(Derived).onSystemExclusive(msg);
115 }
116
118 using MMT = MIDIMessageType;
119 switch (msg.getMessageType()) {
120 case MMT::NONE: break;
121 case MMT::NOTE_OFF:
122 case MMT::NOTE_ON:
123 case MMT::KEY_PRESSURE:
124 case MMT::CONTROL_CHANGE:
125 case MMT::PROGRAM_CHANGE:
126 case MMT::CHANNEL_PRESSURE:
127 case MMT::PITCH_BEND:
128 case MMT::SYSEX_START: break;
129 case MMT::MTC_QUARTER_FRAME:
130 CRTP(Derived).onTimeCodeQuarterFrame(msg.getData1(),
131 msg.getCable());
132 break;
133 case MMT::SONG_POSITION_POINTER:
134 CRTP(Derived).onSongPosition(msg.getData14bit(),
135 msg.getCable());
136 break;
137 case MMT::SONG_SELECT:
138 CRTP(Derived).onSongSelect(msg.getData1(), msg.getCable());
139 break;
140 case MMT::UNDEFINED_SYSCOMMON_1: break;
141 case MMT::UNDEFINED_SYSCOMMON_2: break;
142 case MMT::TUNE_REQUEST:
143 CRTP(Derived).onTuneRequest(msg.getCable());
144 break;
145 case MMT::SYSEX_END:
146 case MMT::TIMING_CLOCK:
147 case MMT::UNDEFINED_REALTIME_1:
148 case MMT::START:
149 case MMT::CONTINUE:
150 case MMT::STOP:
151 case MMT::UNDEFINED_REALTIME_2:
152 case MMT::ACTIVE_SENSING:
153 case MMT::SYSTEM_RESET:
154 default: break;
155 }
156 }
157
159 using MMT = MIDIMessageType;
160 switch (msg.getMessageType()) {
161 case MMT::NONE: break;
162 case MMT::NOTE_OFF:
163 case MMT::NOTE_ON:
164 case MMT::KEY_PRESSURE:
165 case MMT::CONTROL_CHANGE:
166 case MMT::PROGRAM_CHANGE:
167 case MMT::CHANNEL_PRESSURE:
168 case MMT::PITCH_BEND:
169 case MMT::SYSEX_START:
170 case MMT::MTC_QUARTER_FRAME:
171 case MMT::SONG_POSITION_POINTER:
172 case MMT::SONG_SELECT:
173 case MMT::UNDEFINED_SYSCOMMON_1:
174 case MMT::UNDEFINED_SYSCOMMON_2:
175 case MMT::TUNE_REQUEST:
176 case MMT::SYSEX_END: break;
177 case MMT::TIMING_CLOCK:
178 CRTP(Derived).onClock(msg.getCable());
179 break;
180 case MMT::UNDEFINED_REALTIME_1: break;
181 case MMT::START: CRTP(Derived).onStart(msg.getCable()); break;
182 case MMT::CONTINUE: CRTP(Derived).onContinue(msg.getCable()); break;
183 case MMT::STOP: CRTP(Derived).onStop(msg.getCable()); break;
184 case MMT::UNDEFINED_REALTIME_2: break;
185 case MMT::ACTIVE_SENSING:
186 CRTP(Derived).onActiveSensing(msg.getCable());
187 break;
188 case MMT::SYSTEM_RESET: CRTP(Derived).onSystemReset(msg.getCable()); break;
189 default: break;
190 }
191 }
192
194
195 template <class...>
196 struct Dummy {};
197
198 template <class T1, class R1, class... Args1, //
199 class T2, class R2, class... Args2>
200 static constexpr bool same_return_type_and_arguments(R1 (T1::*)(Args1...),
201 R2 (T2::*)(Args2...)) {
202 return std::is_same<Dummy<R1, Args1...>, Dummy<R2, Args2...>>::value;
203 }
204
205 public:
207 // clang-format off
208 static_assert(std::is_base_of<FineGrainedMIDI_Callbacks, Derived>::value, "Invalid CRTP");
209 static_assert(same_return_type_and_arguments(&Derived::onNoteOff, &FineGrainedMIDI_Callbacks::onNoteOff), "Incorrect signature for onNoteOff");
210 static_assert(same_return_type_and_arguments(&Derived::onNoteOn, &FineGrainedMIDI_Callbacks::onNoteOn), "Incorrect signature for onNoteOn");
211 static_assert(same_return_type_and_arguments(&Derived::onKeyPressure, &FineGrainedMIDI_Callbacks::onKeyPressure), "Incorrect signature for onKeyPressure");
212 static_assert(same_return_type_and_arguments(&Derived::onControlChange, &FineGrainedMIDI_Callbacks::onControlChange), "Incorrect signature for onControlChange");
213 static_assert(same_return_type_and_arguments(&Derived::onProgramChange, &FineGrainedMIDI_Callbacks::onProgramChange), "Incorrect signature for onProgramChange");
214 static_assert(same_return_type_and_arguments(&Derived::onChannelPressure, &FineGrainedMIDI_Callbacks::onChannelPressure), "Incorrect signature for onChannelPressure");
215 static_assert(same_return_type_and_arguments(&Derived::onPitchBend, &FineGrainedMIDI_Callbacks::onPitchBend), "Incorrect signature for onPitchBend");
216 static_assert(same_return_type_and_arguments(&Derived::onSystemExclusive, &FineGrainedMIDI_Callbacks::onSystemExclusive), "Incorrect signature for onSystemExclusive");
217 static_assert(same_return_type_and_arguments(&Derived::onTimeCodeQuarterFrame, &FineGrainedMIDI_Callbacks::onTimeCodeQuarterFrame), "Incorrect signature for onTimeCodeQuarterFrame");
218 static_assert(same_return_type_and_arguments(&Derived::onSongPosition, &FineGrainedMIDI_Callbacks::onSongPosition), "Incorrect signature for onSongPosition");
219 static_assert(same_return_type_and_arguments(&Derived::onSongSelect, &FineGrainedMIDI_Callbacks::onSongSelect), "Incorrect signature for onSongSelect");
220 static_assert(same_return_type_and_arguments(&Derived::onTuneRequest, &FineGrainedMIDI_Callbacks::onTuneRequest), "Incorrect signature for onTuneRequest");
221 static_assert(same_return_type_and_arguments(&Derived::onClock, &FineGrainedMIDI_Callbacks::onClock), "Incorrect signature for onClock");
222 static_assert(same_return_type_and_arguments(&Derived::onStart, &FineGrainedMIDI_Callbacks::onStart), "Incorrect signature for onStart");
223 static_assert(same_return_type_and_arguments(&Derived::onContinue, &FineGrainedMIDI_Callbacks::onContinue), "Incorrect signature for onContinue");
224 static_assert(same_return_type_and_arguments(&Derived::onStop, &FineGrainedMIDI_Callbacks::onStop), "Incorrect signature for onStop");
225 static_assert(same_return_type_and_arguments(&Derived::onActiveSensing, &FineGrainedMIDI_Callbacks::onActiveSensing), "Incorrect signature for onActiveSensing");
226 static_assert(same_return_type_and_arguments(&Derived::onSystemReset, &FineGrainedMIDI_Callbacks::onSystemReset), "Incorrect signature for onSystemReset");
227 // clang-format on
228 }
229
231};
232
233// clang-format off
234template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onNoteOff(Channel, uint8_t, uint8_t, Cable) {}
235template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onNoteOn(Channel, uint8_t, uint8_t, Cable) {}
236template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onKeyPressure(Channel, uint8_t, uint8_t, Cable) {}
237template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onControlChange(Channel, uint8_t, uint8_t, Cable) {}
238template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onProgramChange(Channel, uint8_t, Cable) {}
239template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onChannelPressure(Channel, uint8_t, Cable) {}
240template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onPitchBend(Channel, uint16_t, Cable) {}
242template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onTimeCodeQuarterFrame(uint8_t,Cable) {}
243template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onSongPosition(uint16_t,Cable) {}
244template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onSongSelect(uint8_t,Cable) {}
245template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onTuneRequest(Cable) {}
246template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onClock(Cable) {}
247template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onStart(Cable) {}
248template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onContinue(Cable) {}
249template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onStop(Cable) {}
250template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onActiveSensing(Cable) {}
251template <class Derived> inline void FineGrainedMIDI_Callbacks<Derived>::onSystemReset(Cable) {}
252// clang-format on
253
#define CRTP(Derived)
Helper for the Curiously Recurring Template Pattern.
Definition: CRTP.hpp:4
MIDIMessageType
All possible MIDI status byte values (without channel).
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
A type-safe class for MIDI USB Cable numbers.
Definition: Cable.hpp:13
A type-safe class for MIDI channels.
Definition: Channel.hpp:13
void onChannelMessage(MIDI_Interface &, ChannelMessage msg) override
Callback for incoming MIDI Channel Messages (notes, control change, pitch bend, etc....
void onTimeCodeQuarterFrame(uint8_t data, Cable cable)
void onPitchBend(Channel channel, uint16_t bend, Cable cable)
void onSysCommonMessage(MIDI_Interface &, SysCommonMessage msg) override
Callback for incoming MIDI System Common Messages.
void onSystemReset(Cable cable)
void onContinue(Cable cable)
void onSystemExclusive(SysExMessage message)
void onActiveSensing(Cable cable)
void onProgramChange(Channel channel, uint8_t program, Cable cable)
void onNoteOff(Channel channel, uint8_t note, uint8_t velocity, Cable cable)
void onRealTimeMessage(MIDI_Interface &, RealTimeMessage msg) override
Callback for incoming MIDI Real-Time Messages.
void onNoteOn(Channel channel, uint8_t note, uint8_t velocity, Cable cable)
void onControlChange(Channel channel, uint8_t controller, uint8_t value, Cable cable)
void onSongPosition(uint16_t beats, Cable cable)
void onTuneRequest(Cable cable)
void onSongSelect(uint8_t songnumber, Cable cable)
void onKeyPressure(Channel channel, uint8_t note, uint8_t pressure, Cable cable)
void onSysExMessage(MIDI_Interface &, SysExMessage msg) override
Callback for incoming MIDI System Exclusive Messages.
void onChannelPressure(Channel channel, uint8_t pressure, Cable cable)
A class for callbacks from MIDI input.
virtual void onChannelMessage(MIDI_Interface &, ChannelMessage)
Callback for incoming MIDI Channel Messages (notes, control change, pitch bend, etc....
virtual ~MIDI_Callbacks()=default
Destructor.
virtual void onSysExMessage(MIDI_Interface &, SysExMessage)
Callback for incoming MIDI System Exclusive Messages.
virtual void onRealTimeMessage(MIDI_Interface &, RealTimeMessage)
Callback for incoming MIDI Real-Time Messages.
virtual void onSysCommonMessage(MIDI_Interface &, SysCommonMessage)
Callback for incoming MIDI System Common Messages.
An abstract class for MIDI interfaces.
constexpr int8_t note(Note note, int8_t numOctave)
Get the MIDI note in the given octave.
Definition: Notes.hpp:56
MIDIMessageType getMessageType() const
Get the MIDI message type.
Channel getChannel() const
Get the MIDI channel of the message.
Cable getCable() const
Get the MIDI USB cable number of the message.
uint8_t getData1() const
Get the first data byte.
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.
Cable getCable() const
Get the MIDI USB cable number of the message.
MIDIMessageType getMessageType() const
Get the MIDI message type.
MIDIMessageType getMessageType() const
Get the MIDI message type.