Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
Control_Surface_Class.cpp
Go to the documentation of this file.
2#include <AH/Debug/Debug.hpp>
10
11#include <AH/Arduino-Wrapper.h>
12
14
16
18 static Control_Surface_ instance;
19 return instance;
20}
21
23#if defined(ARDUINO) && defined(DEBUG_OUT)
25 delay(250);
26#endif
27
29
31 ExtendedIOElement::beginAll();
35 MIDIInputElementNote::beginAll();
36 MIDIInputElementKP::beginAll();
37 MIDIInputElementCC::beginAll();
38 MIDIInputElementPC::beginAll();
39 MIDIInputElementCP::beginAll();
40 MIDIInputElementPB::beginAll();
45}
46
48#if !DISABLE_PIPES
49 if (hasSinkPipe() || hasSourcePipe())
50 return false;
52 if (def == nullptr) {
53 FATAL_ERROR(F("No default MIDI Interface"), 0xF123);
54 return false;
55 }
56 *this << inpipe << *def;
57 *this >> outpipe >> *def;
58 return true;
59#else
61#endif
62}
63
65#if !DISABLE_PIPES
68#endif
69}
70
72 ExtendedIOElement::updateAllBufferedInputs();
76 if (displayTimer)
78 ExtendedIOElement::updateAllBufferedOutputs();
79}
80
82#if !DISABLE_PIPES
84#else
85 if (auto iface = MIDI_Interface::getDefault()) {
86 MIDIReadEvent event = iface->read();
89 switch (event) {
91 sinkMIDIfromPipe(iface->getChannelMessage());
92 break;
93 case MIDIReadEvent::SYSEX_CHUNK: // fallthrough
95 sinkMIDIfromPipe(iface->getSysExMessage());
96 break;
98 sinkMIDIfromPipe(iface->getSysCommonMessage());
99 break;
101 sinkMIDIfromPipe(iface->getRealTimeMessage());
102 break;
103 case MIDIReadEvent::NO_MESSAGE: break; // LCOV_EXCL_LINE
104 default: break; // LCOV_EXCL_LINE
105 }
106 event = iface->read();
107 }
108 }
109#endif
110}
111
112#if !DISABLE_PIPES
125#else
127 if (auto def = MIDI_Interface::getDefault())
128 def->send(msg);
129}
131 if (auto def = MIDI_Interface::getDefault())
132 def->send(msg);
133}
135 if (auto def = MIDI_Interface::getDefault())
136 def->send(msg);
137}
139 if (auto def = MIDI_Interface::getDefault())
140 def->send(msg);
141}
142#endif
143
145#ifdef DEBUG_MIDI_PACKETS
146 if (midimsg.hasTwoDataBytes())
147 DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << ' '
148 << midimsg.data2 << " (" << midimsg.cable.getOneBased()
149 << ')' << dec);
150 else
151 DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << " ("
152 << midimsg.cable.getOneBased() << ')' << dec);
153#endif
154
155 // If the Channel Message callback exists, call it to see if we have to
156 // continue handling it.
158 return;
159
162 // Reset All Controllers
163 DEBUG(F("Reset All Controllers"));
164 MIDIInputElementCC::resetAll();
165 MIDIInputElementCP::resetAll();
166 } else if (midimsg.getMessageType() == MIDIMessageType::ControlChange &&
167 midimsg.getData1() == MIDI_CC::All_Notes_Off) {
168 // All Notes Off
169 MIDIInputElementNote::resetAll();
170 } else {
171 switch (midimsg.getMessageType()) {
172 case MIDIMessageType::None: break;
173 case MIDIMessageType::NoteOff: // fallthrough
175 DEBUGFN(F("Updating Note elements with new MIDI "
176 "message."));
177 MIDIInputElementNote::updateAllWith(midimsg);
178 break;
180 DEBUGFN(F("Updating Key Pressure elements with new MIDI "
181 "message."));
182 MIDIInputElementKP::updateAllWith(midimsg);
183 break;
185 DEBUGFN(F("Updating CC elements with new MIDI "
186 "message."));
187 MIDIInputElementCC::updateAllWith(midimsg);
188 break;
190 DEBUGFN(F("Updating Program Change elements with new MIDI "
191 "message."));
192 MIDIInputElementPC::updateAllWith(midimsg);
193 break;
195 DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
196 "message."));
197 MIDIInputElementCP::updateAllWith(midimsg);
198 break;
200 // Channel Pressure
201 DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
202 "message."));
203 MIDIInputElementPB::updateAllWith(midimsg);
204 break;
205
206 // These MIDI types are not channel messages, so aren't handled here
207 // LCOV_EXCL_START
208 case MIDIMessageType::SysExStart: break;
211 case MIDIMessageType::SongSelect: break;
215 case MIDIMessageType::SysExEnd: break;
218 case MIDIMessageType::Start: break;
219 case MIDIMessageType::Continue: break;
220 case MIDIMessageType::Stop: break;
224 default:
225 break;
226 // LCOV_EXCL_STOP
227 }
228 }
229}
230
232#ifdef DEBUG_MIDI_PACKETS
233 const uint8_t *data = msg.data;
234 size_t len = msg.length;
235 DEBUG_OUT << ">>> " << hex;
236 for (size_t i = 0; i < len; i++)
237 DEBUG_OUT << data[i] << ' ';
238 DEBUG_OUT << " (" << msg.cable << ')' << dec << endl;
239#endif
240 // If the SysEx Message callback exists, call it to see if we have to
241 // continue handling it.
243 return;
245}
246
248#ifdef DEBUG_MIDI_PACKETS
249 DEBUG_OUT << ">>> " << hex << msg.getMessageType() << ' ' << msg.getData1()
250 << ' ' << msg.getData2() << " (" << msg.cable << ')' << dec
251 << endl;
252#endif
253 // If the SysEx Message callback exists, call it to see if we have to
254 // continue handling it.
256 return;
257}
258
260#ifdef DEBUG_MIDI_PACKETS
261 DEBUG(">>> " << hex << rtMessage.message << " ("
262 << rtMessage.cable.getOneBased() << ')' << dec);
263#endif
264
265 // If the Real-Time Message callback exists, call it to see if we have to
266 // continue handling it.
268 return;
269}
270
272 MIDIInputElementNote::updateAll();
273 MIDIInputElementKP::updateAll();
274 MIDIInputElementCC::updateAll();
275 MIDIInputElementPC::updateAll();
276 MIDIInputElementCP::updateAll();
277 MIDIInputElementPB::updateAll();
279}
280
283 auto it = allElements.begin();
284 auto end = allElements.end();
285 if (it == end)
286 return;
287 auto previousDisplay = &it->getDisplay();
288 // Loop over all display elements
289 while (true) {
290 ++it;
291 // If this is the first element on another display
292 if (it == end || &it->getDisplay() != previousDisplay) {
293 // Initialize the display
295 if (it == end)
296 break;
297 previousDisplay = &it->getDisplay();
298 }
299 }
300}
301
304 auto it = allElements.begin();
305 auto end = allElements.end();
306 if (it == end)
307 return;
308 auto prevIt = it;
309 auto previousDisplay = &prevIt->getDisplay();
310 bool dirty = false;
311 // Loop over all display elements
312 while (true) {
313 dirty |= it->getDirty();
314 ++it;
315 // If this is the first element on another display
316 if (it == end || &it->getDisplay() != previousDisplay) {
317 // If there was at least one element on the previous display that
318 // has to be redrawn
319 if (dirty) {
320 // Clear the display
321 previousDisplay->clearAndDrawBackground();
322 // Update all elements on that display
323 for (auto drawIt = prevIt; drawIt != it; ++drawIt)
324 drawIt->draw();
325 // Write the buffer to the display
326 previousDisplay->display();
327 }
328 if (it == end)
329 break;
330 prevIt = it;
331 previousDisplay = &it->getDisplay();
332 dirty = false;
333 }
334 }
335}
336
337#if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN)
339#endif
340
#define DEBUG_OUT
The debug output.
Control_Surface_ & Control_Surface
A predefined instance of the Control Surface to use in the Arduino sketches.
MIDIReadEvent
Values returned by the MIDI reading functions.
@ CHANNEL_MESSAGE
A MIDI Channel message was received.
@ SYSEX_CHUNK
An incomplete System Exclusive message.
@ SYSCOMMON_MESSAGE
A MIDI System Common message was received.
@ NO_MESSAGE
No new messages were received.
@ SYSEX_MESSAGE
A MIDI System Exclusive message was received.
@ REALTIME_MESSAGE
A MIDI Real-Time message was received.
@ 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).
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
An abstract base class for Extended Input/Output elements.
A class that reads and filters an analog input.
void begin()
Initialize or reset the timer. The timer will fire immediately.
A super class for object that have to be updated regularly.
constexpr uint8_t getOneBased() const
Get the cable as an integer.
Definition Cable.hpp:36
This class ensures initialization, updating, and interaction between all other classes,...
void updateDisplays()
Clear, draw and display all displays that contain display elements that have changed.
Timer< micros > displayTimer
A timer to know when to refresh the displays.
bool connectDefaultMIDI_Interface()
Connect Control Surface to the default MIDI interface.
void disconnectMIDI_Interfaces()
Disconnect Control Surface from the MIDI interfaces it's connected to.
void updateInputs()
Update all MIDIInputElements.
ChannelMessageCallback channelMessageCallback
static Control_Surface_ & getInstance()
Return the static Control_Surface_ instance (Control_Surface_ is a singleton.)
void updateMidiInput()
Update all MIDI interfaces to receive new MIDI events.
void sendSysExImpl(SysExMessage)
Low-level function for sending a system exclusive MIDI message.
void sinkMIDIfromPipe(ChannelMessage msg) override
Accept an incoming MIDI Channel message.
SysCommonMessageCallback sysCommonMessageCallback
void begin()
Initialize the Control_Surface.
RealTimeMessageCallback realTimeMessageCallback
void beginDisplays()
Initialize all displays that have at least one display element.
SysExMessageCallback sysExMessageCallback
void sendSysCommonImpl(SysCommonMessage)
Low-level function for sending a MIDI system common message.
void sendChannelMessageImpl(ChannelMessage)
Low-level function for sending a MIDI channel voice message.
void sendRealTimeImpl(RealTimeMessage)
Low-level function for sending a MIDI real-time message.
void loop()
Update all MIDI elements, send MIDI events and read MIDI input.
static DoublyLinkedList< DisplayElement > & getAll()
Get the list of all DisplayElement instances.
static void updateAll()
Update all.
static void beginAll()
Begin all.
static bool updateAllWith(MessageType midimsg)
Update all.
static void dispatchIncoming(MIDIInterface_t *iface, MIDIReadEvent event)
Dispatch the given type of MIDI message from the given interface.
static MIDI_Interface * getDefault()
Return the default MIDI interface.
void disconnectSourcePipes()
Disconnect all source pipes that sink to this sink (recursively).
bool hasSourcePipe() const
Check if this sink is connected to a source pipe.
void sourceMIDItoPipe(ChannelMessage)
Send a MIDI Channel Message down the pipe.
void disconnectSinkPipes()
Disconnect all sink pipes that this source sinks to (recursively).
bool hasSinkPipe() const
Check if this source is connected to a sink pipe.
#define DEBUG(x)
Print an expression to the debug output if debugging is enabled.
Definition Debug.hpp:95
#define DEBUGFN(x)
Print an expression and its function (function name and line number) to the debug output if debugging...
Definition Debug.hpp:115
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition Error.hpp:57
constexpr unsigned long defaultBaudRate
The default baud rate for debug output.
constexpr uint8_t Reset_All_Controllers
constexpr uint8_t All_Notes_Off
An array wrapper for easy copying, comparing, and iterating.
Definition Array.hpp:32
static constexpr size_t length
Definition Array.hpp:35
T data[N]
Definition Array.hpp:33
T * begin()
Get a pointer to the first element.
Definition Array.hpp:74
T * end()
Get a pointer to the memory beyond the array.
Definition Array.hpp:84
MIDIMessageType getMessageType() const
Get the MIDI message type.
bool hasTwoDataBytes() const
Check whether this message has one or two data bytes.
uint8_t data2
First MIDI data byte.
uint8_t header
MIDI status byte (message type and channel).
uint8_t getData1() const
Get the first data byte.
uint8_t data1
First MIDI data byte.
Cable cable
USB MIDI cable number;.