Line data Source code
1 : #pragma once
2 :
3 : #include "MIDI_Pipes.hpp"
4 : #include <AH/Containers/Updatable.hpp>
5 : #include <Def/Def.hpp>
6 : #include <Def/MIDIAddress.hpp>
7 : #include <MIDI_Parsers/MIDI_Parser.hpp>
8 :
9 : BEGIN_CS_NAMESPACE
10 :
11 : constexpr auto MIDI_BAUD = 31250;
12 :
13 : class MIDI_Callbacks;
14 :
15 : /**
16 : * @brief Statically polymorphic template for classes that send MIDI messages.
17 : */
18 : template <class Derived>
19 : class MIDI_Sender {
20 : public:
21 : /// @name Sending MIDI
22 : /// @{
23 :
24 : /**
25 : * @brief Send a 3-byte MIDI packet.
26 : *
27 : * @param m
28 : * MIDI message type. [0x80, 0xE0]
29 : * @param c
30 : * The MIDI channel. [1, 16]
31 : * @param d1
32 : * The first data byte. [0, 127]
33 : * @param d2
34 : * The second data byte. [0, 127]
35 : * @param cable
36 : * The MIDI Cable Number. [1, 16]
37 : */
38 : void send(MIDIMessageType m, Channel c, uint8_t d1, uint8_t d2,
39 : Cable cable = CABLE_1);
40 :
41 : /**
42 : * @brief Send a 2-byte MIDI packet.
43 : *
44 : * @param m
45 : * MIDI message type. [0x80, 0xE0]
46 : * @param c
47 : * The MIDI channel. [1, 16]
48 : * @param d1
49 : * The first data byte. [0, 127]
50 : * @param cable
51 : * The MIDI Cable Number. [1, 16]
52 : */
53 : void send(MIDIMessageType m, Channel c, uint8_t d1, Cable cable = CABLE_1);
54 :
55 : /**
56 : * @brief Send a 3-byte MIDI packet with cable number.
57 : *
58 : * @param m
59 : * MIDI message type. [0x80, 0xE0]
60 : * @param c
61 : * The MIDI channel. [1, 16]
62 : * @param d1
63 : * The first data byte. [0, 127]
64 : * @param d2
65 : * The second data byte. [0, 127]
66 : * @param cable
67 : * The MIDI Cable Number. [1, 16]
68 : */
69 : void sendOnCable(MIDIMessageType m, Channel c, uint8_t d1, uint8_t d2,
70 : Cable cable);
71 :
72 : /**
73 : * @brief Send a 2-byte MIDI packet with cable number.
74 : *
75 : * @param m
76 : * MIDI message type. [0x80, 0xE0]
77 : * @param c
78 : * The MIDI channel. [1, 16]
79 : * @param d1
80 : * The first data byte. [0, 127]
81 : * @param cable
82 : * The MIDI Cable Number. [1, 16]
83 : */
84 : void sendOnCable(MIDIMessageType m, Channel c, uint8_t d1, Cable cable);
85 :
86 : /**
87 : * @brief Send a single-byte MIDI packet with cable number.
88 : *
89 : * @param rt
90 : * The MIDI byte to send.
91 : * @param cable
92 : * The MIDI Cable Number. [1, 16]
93 : */
94 : void sendOnCable(MIDIMessageType rt, Cable cable);
95 :
96 : /// Send a MIDI Note On event.
97 : void sendNoteOn(MIDIAddress address, uint8_t velocity);
98 : /// Send a MIDI Note Off event.
99 : void sendNoteOff(MIDIAddress address, uint8_t velocity);
100 : /// Send a MIDI Key Pressure event.
101 : void sendKP(MIDIAddress address, uint8_t pressure);
102 : /// Send a MIDI Control Change event.
103 : void sendCC(MIDIAddress address, uint8_t value);
104 : /// Send a MIDI Program Change event.
105 : void sendPC(MIDIAddress address);
106 : /// Send a MIDI Program Change event.
107 : void sendPC(MIDIChannelCN address, uint8_t value);
108 : /// Send a MIDI Channel Pressure event.
109 : void sendCP(MIDIChannelCN address, uint8_t pressure);
110 : /// Send a MIDI Pitch Bend event.
111 : void sendPB(MIDIChannelCN address, uint16_t value);
112 : /// Send a MIDI Channel Message
113 : void send(ChannelMessage message);
114 : /// Send a MIDI System Exclusive message.
115 : void send(SysExMessage message);
116 : /// Send a MIDI System Exclusive message.
117 : template <size_t N>
118 11 : void send(const uint8_t (&sysexdata)[N], Cable cable = CABLE_1) {
119 11 : send(SysExMessage{sysexdata, N, cable});
120 11 : }
121 : /// Send a MIDI Real-Time message.
122 : void send(RealTimeMessage message);
123 : /// Send a single-byte MIDI message.
124 : void send(MIDIMessageType rt, Cable cable = CABLE_1);
125 :
126 : /// @}
127 : };
128 :
129 : /**
130 : * @brief An abstract class for MIDI interfaces.
131 : */
132 : class MIDI_Interface : public TrueMIDI_SinkSource,
133 : public MIDI_Sender<MIDI_Interface>,
134 : public AH::Updatable<MIDI_Interface> {
135 : protected:
136 : /**
137 : * @brief Constructor.
138 : */
139 96 : MIDI_Interface() = default;
140 :
141 : MIDI_Interface(MIDI_Interface &&) = default;
142 :
143 : public:
144 : /**
145 : * @brief Destructor.
146 : */
147 : virtual ~MIDI_Interface();
148 :
149 : /**
150 : * @brief Initialize the MIDI Interface.
151 : */
152 1 : void begin() override {}
153 :
154 : /**
155 : * @brief Read the MIDI interface and call the callback if a message is
156 : * received.
157 : */
158 : void update() override = 0;
159 :
160 : /// @name Default MIDI Interfaces
161 : /// @{
162 : /**
163 : * @brief Return the default MIDI interface.
164 : */
165 : static MIDI_Interface *getDefault();
166 :
167 : /**
168 : * @brief Set this MIDI interface as the default interface.
169 : */
170 : void setAsDefault();
171 : /// @}
172 :
173 : /// @name MIDI Input Callbacks
174 : /// @{
175 : /**
176 : * @brief Set the callbacks that will be called when a MIDI message is
177 : * received.
178 : *
179 : * @param cb
180 : * A pointer to an object that implements the MIDI_Callbacks class.
181 : */
182 : virtual void setCallbacks(MIDI_Callbacks *cb) = 0;
183 :
184 : /**
185 : * @brief Set the callbacks that will be called when a MIDI message is
186 : * received.
187 : *
188 : * @param cb
189 : * A reference to an object that implements the MIDI_Callbacks
190 : * class.
191 : */
192 1 : void setCallbacks(MIDI_Callbacks &cb) { setCallbacks(&cb); }
193 : /// @}
194 :
195 : protected:
196 : friend class MIDI_Sender<MIDI_Interface>;
197 : /**
198 : * @brief Low-level function for sending a 3-byte MIDI message.
199 : */
200 : virtual void sendImpl(uint8_t header, uint8_t d1, uint8_t d2,
201 : uint8_t cn) = 0;
202 : /**
203 : * @brief Low-level function for sending a 2-byte MIDI message.
204 : */
205 : virtual void sendImpl(uint8_t header, uint8_t d1, uint8_t cn) = 0;
206 :
207 : /**
208 : * @brief Low-level function for sending a system exclusive MIDI message.
209 : */
210 : virtual void sendImpl(const uint8_t *data, size_t length, uint8_t cn) = 0;
211 :
212 : /**
213 : * @brief Low-level function for sending a single-byte MIDI message.
214 : */
215 : virtual void sendImpl(uint8_t rt, uint8_t cn) = 0;
216 :
217 : protected:
218 : /// Accept an incoming MIDI Channel message.
219 : void sinkMIDIfromPipe(ChannelMessage) override;
220 : /// Accept an incoming MIDI System Exclusive message.
221 : void sinkMIDIfromPipe(SysExMessage) override;
222 : /// Accept an incoming MIDI Real-Time message.
223 : void sinkMIDIfromPipe(RealTimeMessage) override;
224 :
225 : private:
226 : static MIDI_Interface *DefaultMIDI_Interface;
227 : };
228 :
229 : /**
230 : * @brief An abstract class for MIDI interfaces.
231 : */
232 96 : class Parsing_MIDI_Interface : public MIDI_Interface {
233 : protected:
234 : /**
235 : * @brief Construct a MIDI interface with the given parser.
236 : *
237 : * Also set this interface as the default MIDI interface.
238 : *
239 : * @param parser
240 : * The MIDI parser to use for the interface.
241 : */
242 96 : Parsing_MIDI_Interface(MIDI_Parser &parser) : parser(parser) {}
243 :
244 : public:
245 : /// @name Parsing MIDI Input
246 : /// @{
247 :
248 : MIDI_Parser &getParser() { return parser; }
249 :
250 : /// Return the received channel message.
251 33 : ChannelMessage getChannelMessage() const {
252 33 : return parser.getChannelMessage();
253 : }
254 :
255 : /// Return the received real-time message.
256 8 : RealTimeMessage getRealTimeMessage() const {
257 8 : return parser.getRealTimeMessage();
258 : }
259 :
260 : /// Return the received system exclusive message.
261 20 : SysExMessage getSysExMessage() const { return parser.getSysExMessage(); }
262 :
263 : /// @}
264 :
265 : void update() override;
266 :
267 10 : void setCallbacks(MIDI_Callbacks *cb) override { this->callbacks = cb; }
268 : using MIDI_Interface::setCallbacks;
269 :
270 : protected:
271 : bool dispatchMIDIEvent(MIDIReadEvent event);
272 :
273 : private:
274 : /**
275 : * @brief Try reading and parsing a single incoming MIDI message.
276 : * @return Returns the type of the read message, or
277 : * `MIDIReadEvent::NO_MESSAGE` if no MIDI message was available.
278 : */
279 : virtual MIDIReadEvent read() = 0;
280 :
281 : bool onRealTimeMessage();
282 : bool onChannelMessage();
283 : bool onSysExMessage();
284 :
285 : protected:
286 : MIDI_Parser &parser;
287 96 : MIDI_Callbacks *callbacks = nullptr;
288 96 : MIDIReadEvent event = MIDIReadEvent::NO_MESSAGE;
289 : };
290 :
291 : // LCOV_EXCL_START
292 : /**
293 : * @brief A class for callbacks from MIDI input.
294 : */
295 : class MIDI_Callbacks {
296 : public:
297 : /// Callback for incoming MIDI Channel Messages (notes, control change,
298 : /// pitch bend, etc.)
299 : virtual void onChannelMessage(Parsing_MIDI_Interface &midi) { (void)midi; }
300 : /// Callback for incoming MIDI System Exclusive Messages.
301 : virtual void onSysExMessage(Parsing_MIDI_Interface &midi) { (void)midi; }
302 : /// Callback for incoming MIDI Real-Time Messages.
303 : virtual void onRealTimeMessage(Parsing_MIDI_Interface &midi) { (void)midi; }
304 :
305 : /// Destructor.
306 : virtual ~MIDI_Callbacks() = default;
307 : };
308 : // LCOV_EXCL_STOP
309 :
310 : END_CS_NAMESPACE
311 :
312 : #include "MIDI_Interface.ipp"
|