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
46
48#if !DISABLE_PIPES
49 if (hasSinkPipe() || hasSourcePipe())
50 return false;
51 auto def = MIDI_Interface::getDefault();
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();
87 while (event != MIDIReadEvent::NO_MESSAGE) {
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"));
166 } else if (midimsg.getMessageType() == MIDIMessageType::ControlChange &&
167 midimsg.getData1() == MIDI_CC::All_Notes_Off) {
168 // All Notes Off
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."));
178 break;
180 DEBUGFN(F("Updating Key Pressure elements with new MIDI "
181 "message."));
183 break;
185 DEBUGFN(F("Updating CC elements with new MIDI "
186 "message."));
188 break;
190 DEBUGFN(F("Updating Program Change elements with new MIDI "
191 "message."));
193 break;
195 DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
196 "message."));
198 break;
200 // Channel Pressure
201 DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
202 "message."));
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
280
282 auto &allElements = DisplayElement::getAll();
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
294 previousDisplay->begin();
295 if (it == end)
296 break;
297 previousDisplay = &it->getDisplay();
298 }
299 }
300}
301
303 auto &allElements = DisplayElement::getAll();
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 void resetAll()
Reset 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
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;.
uint8_t getData2() const
Get the second data byte.
MIDIMessageType getMessageType() const
Get the MIDI message type.
const uint8_t * data