Control Surface new-input
MIDI Control Surface library for Arduino
Control_Surface_Class.cpp
Go to the documentation of this file.
2 #include <AH/Debug/Debug.hpp>
8 #include <Selectors/Selector.hpp>
9 
10 #include <AH/Arduino-Wrapper.h>
11 
13 
15 
17  static Control_Surface_ instance;
18  return instance;
19 }
20 
22 #if defined(ARDUINO) && defined(DEBUG_OUT)
24  delay(250);
25 #endif
26 
28 
30  ExtendedIOElement::beginAll();
32  beginDisplays();
44  potentiometerTimer.begin();
45  displayTimer.begin();
46 }
47 
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 }
60 
64 }
65 
67  ExtendedIOElement::updateAllBufferedInputs();
72  updateInputs();
73  if (displayTimer)
75  ExtendedIOElement::updateAllBufferedOutputs();
76 }
77 
80 }
81 
83  this->sourceMIDItoPipe(msg);
84 }
86  this->sourceMIDItoPipe(msg);
87 }
89  this->sourceMIDItoPipe(msg);
90 }
92  this->sourceMIDItoPipe(msg);
93 }
94 
96 #ifdef DEBUG_MIDI_PACKETS
97  if (midimsg.hasTwoDataBytes())
98  DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << ' '
99  << midimsg.data2 << " (" << midimsg.cable.getOneBased()
100  << ')' << dec);
101  else
102  DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << " ("
103  << midimsg.cable.getOneBased() << ')' << dec);
104 #endif
105 
106  // If the Channel Message callback exists, call it to see if we have to
107  // continue handling it.
109  return;
110 
113  // Reset All Controllers
114  DEBUG(F("Reset All Controllers"));
117  } else if (midimsg.getMessageType() == MIDIMessageType::CONTROL_CHANGE &&
118  midimsg.getData1() == MIDI_CC::All_Notes_Off) {
119  // All Notes Off
121  } else {
122  switch (midimsg.getMessageType()) {
123  case MIDIMessageType::NONE: break;
124  case MIDIMessageType::NOTE_OFF: // fallthrough
126  DEBUGFN(F("Updating Note elements with new MIDI "
127  "message."));
129  break;
131  DEBUGFN(F("Updating Key Pressure elements with new MIDI "
132  "message."));
134  break;
136  DEBUGFN(F("Updating CC elements with new MIDI "
137  "message."));
139  break;
141  DEBUGFN(F("Updating Program Change elements with new MIDI "
142  "message."));
144  break;
146  DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
147  "message."));
149  break;
151  // Channel Pressure
152  DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
153  "message."));
155  break;
156 
157  // These MIDI types are not channel messages, so aren't handled here
158  // LCOV_EXCL_START
159  case MIDIMessageType::SYSEX_START: break;
162  case MIDIMessageType::SONG_SELECT: break;
165  case MIDIMessageType::TUNE_REQUEST: break;
166  case MIDIMessageType::SYSEX_END: break;
167  case MIDIMessageType::TIMING_CLOCK: break;
169  case MIDIMessageType::START: break;
170  case MIDIMessageType::CONTINUE: break;
171  case MIDIMessageType::STOP: break;
174  case MIDIMessageType::SYSTEM_RESET: break;
175  default:
176  break;
177  // LCOV_EXCL_STOP
178  }
179  }
180 }
181 
183 #ifdef DEBUG_MIDI_PACKETS
184  const uint8_t *data = msg.data;
185  size_t len = msg.length;
186  DEBUG_OUT << ">>> " << hex;
187  for (size_t i = 0; i < len; i++)
188  DEBUG_OUT << data[i] << ' ';
189  DEBUG_OUT << " (" << msg.cable << ')' << dec << endl;
190 #endif
191  // If the SysEx Message callback exists, call it to see if we have to
192  // continue handling it.
194  return;
196 }
197 
199 #ifdef DEBUG_MIDI_PACKETS
200  DEBUG_OUT << ">>> " << hex << msg.getMessageType() << ' ' << msg.getData1()
201  << ' ' << msg.getData2() << " (" << msg.cable << ')' << dec
202  << endl;
203 #endif
204  // If the SysEx Message callback exists, call it to see if we have to
205  // continue handling it.
207  return;
208 }
209 
211 #ifdef DEBUG_MIDI_PACKETS
212  DEBUG(">>> " << hex << rtMessage.message << " ("
213  << rtMessage.cable.getOneBased() << ')' << dec);
214 #endif
215 
216  // If the Real-Time Message callback exists, call it to see if we have to
217  // continue handling it.
219  return;
220 }
221 
230 }
231 
233  auto &allElements = DisplayElement::getAll();
234  auto it = allElements.begin();
235  auto end = allElements.end();
236  if (it == end)
237  return;
238  auto previousDisplay = &it->getDisplay();
239  // Loop over all display elements
240  while (true) {
241  ++it;
242  // If this is the first element on another display
243  if (it == end || &it->getDisplay() != previousDisplay) {
244  // Initialize the display
245  previousDisplay->begin();
246  if (it == end)
247  break;
248  previousDisplay = &it->getDisplay();
249  }
250  }
251 }
252 
254  auto &allElements = DisplayElement::getAll();
255  auto it = allElements.begin();
256  auto end = allElements.end();
257  if (it == end)
258  return;
259  auto prevIt = it;
260  auto previousDisplay = &prevIt->getDisplay();
261  bool dirty = false;
262  // Loop over all display elements
263  while (true) {
264  dirty |= it->getDirty();
265  ++it;
266  // If this is the first element on another display
267  if (it == end || &it->getDisplay() != previousDisplay) {
268  // If there was at least one element on the previous display that
269  // has to be redrawn
270  if (dirty) {
271  // Clear the display
272  previousDisplay->clearAndDrawBackground();
273  // Update all elements on that display
274  for (auto drawIt = prevIt; drawIt != it; ++drawIt)
275  drawIt->draw();
276  // Write the buffer to the display
277  previousDisplay->display();
278  }
279  if (it == end)
280  break;
281  prevIt = it;
282  previousDisplay = &it->getDisplay();
283  dirty = false;
284  }
285  }
286 }
287 
289 
#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.
Timer< micros > potentiometerTimer
A timer to know when to update the analog inputs.
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 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