Control Surface master
MIDI Control Surface library for Arduino
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();
44 displayTimer.begin();
45}
46
48 if (hasSinkPipe() || hasSourcePipe())
49 return false;
50 auto def = MIDI_Interface::getDefault();
51 if (def == nullptr) {
52 FATAL_ERROR(F("No default MIDI Interface"), 0xF123);
53 return false;
54 }
55 *this << inpipe << *def;
56 *this >> outpipe >> *def;
57 return true;
58}
59
63}
64
66 ExtendedIOElement::updateAllBufferedInputs();
70 if (displayTimer)
72 ExtendedIOElement::updateAllBufferedOutputs();
73}
74
77}
78
80 this->sourceMIDItoPipe(msg);
81}
83 this->sourceMIDItoPipe(msg);
84}
86 this->sourceMIDItoPipe(msg);
87}
89 this->sourceMIDItoPipe(msg);
90}
91
93#ifdef DEBUG_MIDI_PACKETS
94 if (midimsg.hasTwoDataBytes())
95 DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << ' '
96 << midimsg.data2 << " (" << midimsg.cable.getOneBased()
97 << ')' << dec);
98 else
99 DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << " ("
100 << midimsg.cable.getOneBased() << ')' << dec);
101#endif
102
103 // If the Channel Message callback exists, call it to see if we have to
104 // continue handling it.
106 return;
107
110 // Reset All Controllers
111 DEBUG(F("Reset All Controllers"));
114 } else if (midimsg.getMessageType() == MIDIMessageType::CONTROL_CHANGE &&
115 midimsg.getData1() == MIDI_CC::All_Notes_Off) {
116 // All Notes Off
118 } else {
119 switch (midimsg.getMessageType()) {
120 case MIDIMessageType::NONE: break;
121 case MIDIMessageType::NOTE_OFF: // fallthrough
123 DEBUGFN(F("Updating Note elements with new MIDI "
124 "message."));
126 break;
128 DEBUGFN(F("Updating Key Pressure elements with new MIDI "
129 "message."));
131 break;
133 DEBUGFN(F("Updating CC elements with new MIDI "
134 "message."));
136 break;
138 DEBUGFN(F("Updating Program Change elements with new MIDI "
139 "message."));
141 break;
143 DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
144 "message."));
146 break;
148 // Channel Pressure
149 DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
150 "message."));
152 break;
153
154 // These MIDI types are not channel messages, so aren't handled here
155 // LCOV_EXCL_START
163 case MIDIMessageType::SYSEX_END: break;
166 case MIDIMessageType::START: break;
167 case MIDIMessageType::CONTINUE: break;
168 case MIDIMessageType::STOP: break;
172 default:
173 break;
174 // LCOV_EXCL_STOP
175 }
176 }
177}
178
180#ifdef DEBUG_MIDI_PACKETS
181 const uint8_t *data = msg.data;
182 size_t len = msg.length;
183 DEBUG_OUT << ">>> " << hex;
184 for (size_t i = 0; i < len; i++)
185 DEBUG_OUT << data[i] << ' ';
186 DEBUG_OUT << " (" << msg.cable << ')' << dec << endl;
187#endif
188 // If the SysEx Message callback exists, call it to see if we have to
189 // continue handling it.
191 return;
193}
194
196#ifdef DEBUG_MIDI_PACKETS
197 DEBUG_OUT << ">>> " << hex << msg.getMessageType() << ' ' << msg.getData1()
198 << ' ' << msg.getData2() << " (" << msg.cable << ')' << dec
199 << endl;
200#endif
201 // If the SysEx Message callback exists, call it to see if we have to
202 // continue handling it.
204 return;
205}
206
208#ifdef DEBUG_MIDI_PACKETS
209 DEBUG(">>> " << hex << rtMessage.message << " ("
210 << rtMessage.cable.getOneBased() << ')' << dec);
211#endif
212
213 // If the Real-Time Message callback exists, call it to see if we have to
214 // continue handling it.
216 return;
217}
218
227}
228
230 auto &allElements = DisplayElement::getAll();
231 auto it = allElements.begin();
232 auto end = allElements.end();
233 if (it == end)
234 return;
235 auto previousDisplay = &it->getDisplay();
236 // Loop over all display elements
237 while (true) {
238 ++it;
239 // If this is the first element on another display
240 if (it == end || &it->getDisplay() != previousDisplay) {
241 // Initialize the display
242 previousDisplay->begin();
243 if (it == end)
244 break;
245 previousDisplay = &it->getDisplay();
246 }
247 }
248}
249
251 auto &allElements = DisplayElement::getAll();
252 auto it = allElements.begin();
253 auto end = allElements.end();
254 if (it == end)
255 return;
256 auto prevIt = it;
257 auto previousDisplay = &prevIt->getDisplay();
258 bool dirty = false;
259 // Loop over all display elements
260 while (true) {
261 dirty |= it->getDirty();
262 ++it;
263 // If this is the first element on another display
264 if (it == end || &it->getDisplay() != previousDisplay) {
265 // If there was at least one element on the previous display that
266 // has to be redrawn
267 if (dirty) {
268 // Clear the display
269 previousDisplay->clearAndDrawBackground();
270 // Update all elements on that display
271 for (auto drawIt = prevIt; drawIt != it; ++drawIt)
272 drawIt->draw();
273 // Write the buffer to the display
274 previousDisplay->display();
275 }
276 if (it == end)
277 break;
278 prevIt = it;
279 previousDisplay = &it->getDisplay();
280 dirty = false;
281 }
282 }
283}
284
285#if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN)
287#endif
288
#define DEBUG_OUT
The debug output.
Control_Surface_ & Control_Surface
A predefined instance of the Control Surface to use in the Arduino sketches.
#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.
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:173
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 beginAll()
static MIDI_Interface * getDefault()
Return the default MIDI interface.
void disconnectSourcePipes()
Disconnect all source pipes that sink to this sink (recursively).
Definition: MIDI_Pipes.cpp:25
bool hasSourcePipe() const
Check if this sink is connected to a source pipe.
Definition: MIDI_Pipes.hpp:117
void sourceMIDItoPipe(ChannelMessage)
Send a MIDI Channel Message down the pipe.
Definition: MIDI_Pipes.cpp:132
void disconnectSinkPipes()
Disconnect all sink pipes that this source sinks to (recursively).
Definition: MIDI_Pipes.cpp:84
bool hasSinkPipe() const
Check if this source is connected to a sink pipe.
Definition: MIDI_Pipes.hpp:231
#define DEBUG(x)
Print an expression to the debug output if debugging is enabled.
Definition: Debug.hpp:98
#define DEBUGFN(x)
Print an expression and its function (function name and line number) to the debug output if debugging...
Definition: Debug.hpp:118
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition: Error.hpp:60
Print & hex(Print &printer)
Definition: PrintStream.cpp:62
Print & endl(Print &printer)
Definition: PrintStream.cpp:27
Print & dec(Print &printer)
Definition: PrintStream.cpp:77
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