Line data Source code
1 : #include "Control_Surface_Class.hpp"
2 : #include <AH/Debug/Debug.hpp>
3 : #include <AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp>
4 : #include <AH/Hardware/FilteredAnalog.hpp>
5 : #include <MIDI_Constants/Control_Change.hpp>
6 : #include <MIDI_Inputs/MIDIInputElement.hpp>
7 : #include <MIDI_Interfaces/DebugMIDI_Interface.hpp>
8 : #include <MIDI_Outputs/Abstract/MIDIOutputElement.hpp>
9 : #include <Selectors/Selector.hpp>
10 :
11 : #include <AH/Arduino-Wrapper.h>
12 :
13 : BEGIN_CS_NAMESPACE
14 :
15 : using AH::ExtendedIOElement;
16 :
17 598 : Control_Surface_ &Control_Surface_::getInstance() {
18 598 : static Control_Surface_ instance;
19 598 : return instance;
20 : }
21 :
22 0 : void Control_Surface_::begin() {
23 : #if defined(ARDUINO) && defined(DEBUG_OUT)
24 : DEBUG_OUT.begin(AH::defaultBaudRate);
25 : delay(250);
26 : #endif
27 :
28 0 : connectDefaultMIDI_Interface();
29 :
30 0 : FilteredAnalog<>::setupADC();
31 0 : ExtendedIOElement::beginAll();
32 0 : Updatable<MIDI_Interface>::beginAll();
33 0 : MIDIOutputOnly::beginAll();
34 0 : beginDisplays();
35 0 : MIDIInputElementNote::beginAll();
36 0 : MIDIInputElementKP::beginAll();
37 0 : MIDIInputElementCC::beginAll();
38 0 : MIDIInputElementPC::beginAll();
39 0 : MIDIInputElementCP::beginAll();
40 0 : MIDIInputElementPB::beginAll();
41 0 : MIDIInputElementSysEx::beginAll();
42 0 : Updatable<>::beginAll();
43 0 : Updatable<Display>::beginAll();
44 0 : displayTimer.begin();
45 0 : }
46 :
47 39 : bool Control_Surface_::connectDefaultMIDI_Interface() {
48 : #if !DISABLE_PIPES
49 39 : if (hasSinkPipe() || hasSourcePipe())
50 0 : return false;
51 39 : auto def = MIDI_Interface::getDefault();
52 39 : if (def == nullptr) {
53 0 : FATAL_ERROR(F("No default MIDI Interface"), 0xF123);
54 : return false;
55 : }
56 39 : *this << inpipe << *def;
57 39 : *this >> outpipe >> *def;
58 39 : return true;
59 : #else
60 : return MIDI_Interface::getDefault();
61 : #endif
62 : }
63 :
64 0 : void Control_Surface_::disconnectMIDI_Interfaces() {
65 : #if !DISABLE_PIPES
66 0 : disconnectSinkPipes();
67 0 : disconnectSourcePipes();
68 : #endif
69 0 : }
70 :
71 0 : void Control_Surface_::loop() {
72 0 : ExtendedIOElement::updateAllBufferedInputs();
73 0 : Updatable<>::updateAll();
74 0 : updateMidiInput();
75 0 : updateInputs();
76 0 : if (displayTimer)
77 0 : updateDisplays();
78 0 : ExtendedIOElement::updateAllBufferedOutputs();
79 0 : }
80 :
81 0 : void Control_Surface_::updateMidiInput() {
82 : #if !DISABLE_PIPES
83 0 : Updatable<MIDI_Interface>::updateAll();
84 : #else
85 : if (auto iface = MIDI_Interface::getDefault()) {
86 : MIDIReadEvent event = iface->read();
87 : while (event != MIDIReadEvent::NO_MESSAGE) {
88 : MIDI_Interface::dispatchIncoming(iface, event);
89 : switch (event) {
90 : case MIDIReadEvent::CHANNEL_MESSAGE:
91 : sinkMIDIfromPipe(iface->getChannelMessage());
92 : break;
93 : case MIDIReadEvent::SYSEX_CHUNK: // fallthrough
94 : case MIDIReadEvent::SYSEX_MESSAGE:
95 : sinkMIDIfromPipe(iface->getSysExMessage());
96 : break;
97 : case MIDIReadEvent::SYSCOMMON_MESSAGE:
98 : sinkMIDIfromPipe(iface->getSysCommonMessage());
99 : break;
100 : case MIDIReadEvent::REALTIME_MESSAGE:
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 0 : }
111 :
112 : #if !DISABLE_PIPES
113 125 : void Control_Surface_::sendChannelMessageImpl(ChannelMessage msg) {
114 125 : this->sourceMIDItoPipe(msg);
115 125 : }
116 0 : void Control_Surface_::sendSysExImpl(SysExMessage msg) {
117 0 : this->sourceMIDItoPipe(msg);
118 0 : }
119 0 : void Control_Surface_::sendSysCommonImpl(SysCommonMessage msg) {
120 0 : this->sourceMIDItoPipe(msg);
121 0 : }
122 0 : void Control_Surface_::sendRealTimeImpl(RealTimeMessage msg) {
123 0 : this->sourceMIDItoPipe(msg);
124 0 : }
125 : #else
126 : void Control_Surface_::sendChannelMessageImpl(ChannelMessage msg) {
127 : if (auto def = MIDI_Interface::getDefault())
128 : def->send(msg);
129 : }
130 : void Control_Surface_::sendSysExImpl(SysExMessage msg) {
131 : if (auto def = MIDI_Interface::getDefault())
132 : def->send(msg);
133 : }
134 : void Control_Surface_::sendSysCommonImpl(SysCommonMessage msg) {
135 : if (auto def = MIDI_Interface::getDefault())
136 : def->send(msg);
137 : }
138 : void Control_Surface_::sendRealTimeImpl(RealTimeMessage msg) {
139 : if (auto def = MIDI_Interface::getDefault())
140 : def->send(msg);
141 : }
142 : #endif
143 :
144 0 : void Control_Surface_::sinkMIDIfromPipe(ChannelMessage midimsg) {
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.
157 0 : if (channelMessageCallback && channelMessageCallback(midimsg))
158 0 : return;
159 :
160 0 : if (midimsg.getMessageType() == MIDIMessageType::ControlChange &&
161 0 : midimsg.getData1() == MIDI_CC::Reset_All_Controllers) {
162 : // Reset All Controllers
163 : DEBUG(F("Reset All Controllers"));
164 0 : MIDIInputElementCC::resetAll();
165 0 : MIDIInputElementCP::resetAll();
166 0 : } else if (midimsg.getMessageType() == MIDIMessageType::ControlChange &&
167 0 : midimsg.getData1() == MIDI_CC::All_Notes_Off) {
168 : // All Notes Off
169 0 : MIDIInputElementNote::resetAll();
170 : } else {
171 0 : switch (midimsg.getMessageType()) {
172 0 : case MIDIMessageType::None: break;
173 0 : case MIDIMessageType::NoteOff: // fallthrough
174 : case MIDIMessageType::NoteOn:
175 : DEBUGFN(F("Updating Note elements with new MIDI "
176 : "message."));
177 0 : MIDIInputElementNote::updateAllWith(midimsg);
178 0 : break;
179 0 : case MIDIMessageType::KeyPressure:
180 : DEBUGFN(F("Updating Key Pressure elements with new MIDI "
181 : "message."));
182 0 : MIDIInputElementKP::updateAllWith(midimsg);
183 0 : break;
184 0 : case MIDIMessageType::ControlChange:
185 : DEBUGFN(F("Updating CC elements with new MIDI "
186 : "message."));
187 0 : MIDIInputElementCC::updateAllWith(midimsg);
188 0 : break;
189 0 : case MIDIMessageType::ProgramChange:
190 : DEBUGFN(F("Updating Program Change elements with new MIDI "
191 : "message."));
192 0 : MIDIInputElementPC::updateAllWith(midimsg);
193 0 : break;
194 0 : case MIDIMessageType::ChannelPressure:
195 : DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
196 : "message."));
197 0 : MIDIInputElementCP::updateAllWith(midimsg);
198 0 : break;
199 0 : case MIDIMessageType::PitchBend:
200 : // Channel Pressure
201 : DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
202 : "message."));
203 0 : MIDIInputElementPB::updateAllWith(midimsg);
204 0 : break;
205 :
206 : // These MIDI types are not channel messages, so aren't handled here
207 : // LCOV_EXCL_START
208 : case MIDIMessageType::SysExStart: break;
209 : case MIDIMessageType::MTCQuarterFrame: break;
210 : case MIDIMessageType::SongPositionPointer: break;
211 : case MIDIMessageType::SongSelect: break;
212 : case MIDIMessageType::UndefinedSysCommon1: break;
213 : case MIDIMessageType::UndefinedSysCommon2: break;
214 : case MIDIMessageType::TuneRequest: break;
215 : case MIDIMessageType::SysExEnd: break;
216 : case MIDIMessageType::TimingClock: break;
217 : case MIDIMessageType::UndefinedRealTime1: break;
218 : case MIDIMessageType::Start: break;
219 : case MIDIMessageType::Continue: break;
220 : case MIDIMessageType::Stop: break;
221 : case MIDIMessageType::UndefinedRealTime2: break;
222 : case MIDIMessageType::ActiveSensing: break;
223 : case MIDIMessageType::SystemReset: break;
224 : default:
225 : break;
226 : // LCOV_EXCL_STOP
227 : }
228 : }
229 : }
230 :
231 0 : void Control_Surface_::sinkMIDIfromPipe(SysExMessage msg) {
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.
242 0 : if (sysExMessageCallback && sysExMessageCallback(msg))
243 0 : return;
244 0 : MIDIInputElementSysEx::updateAllWith(msg);
245 : }
246 :
247 0 : void Control_Surface_::sinkMIDIfromPipe(SysCommonMessage msg) {
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.
255 0 : if (sysCommonMessageCallback && sysCommonMessageCallback(msg))
256 0 : return;
257 : }
258 :
259 0 : void Control_Surface_::sinkMIDIfromPipe(RealTimeMessage rtMessage) {
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.
267 0 : if (realTimeMessageCallback && realTimeMessageCallback(rtMessage))
268 0 : return;
269 : }
270 :
271 0 : void Control_Surface_::updateInputs() {
272 0 : MIDIInputElementNote::updateAll();
273 0 : MIDIInputElementKP::updateAll();
274 0 : MIDIInputElementCC::updateAll();
275 0 : MIDIInputElementPC::updateAll();
276 0 : MIDIInputElementCP::updateAll();
277 0 : MIDIInputElementPB::updateAll();
278 0 : MIDIInputElementSysEx::updateAll();
279 0 : }
280 :
281 0 : void Control_Surface_::beginDisplays() {
282 0 : auto &allElements = DisplayElement::getAll();
283 0 : auto it = allElements.begin();
284 0 : auto end = allElements.end();
285 0 : if (it == end)
286 0 : return;
287 0 : auto previousDisplay = &it->getDisplay();
288 : // Loop over all display elements
289 : while (true) {
290 0 : ++it;
291 : // If this is the first element on another display
292 0 : if (it == end || &it->getDisplay() != previousDisplay) {
293 : // Initialize the display
294 0 : previousDisplay->begin();
295 0 : if (it == end)
296 0 : break;
297 0 : previousDisplay = &it->getDisplay();
298 : }
299 : }
300 : }
301 :
302 0 : void Control_Surface_::updateDisplays() {
303 0 : auto &allElements = DisplayElement::getAll();
304 0 : auto it = allElements.begin();
305 0 : auto end = allElements.end();
306 0 : if (it == end)
307 0 : return;
308 0 : auto prevIt = it;
309 0 : auto previousDisplay = &prevIt->getDisplay();
310 0 : bool dirty = false;
311 : // Loop over all display elements
312 : while (true) {
313 0 : dirty |= it->getDirty();
314 0 : ++it;
315 : // If this is the first element on another display
316 0 : 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 0 : if (dirty) {
320 : // Clear the display
321 0 : previousDisplay->clearAndDrawBackground();
322 : // Update all elements on that display
323 0 : for (auto drawIt = prevIt; drawIt != it; ++drawIt)
324 0 : drawIt->draw();
325 : // Write the buffer to the display
326 0 : previousDisplay->display();
327 : }
328 0 : if (it == end)
329 0 : break;
330 0 : prevIt = it;
331 0 : previousDisplay = &it->getDisplay();
332 0 : dirty = false;
333 : }
334 0 : }
335 : }
336 :
337 : #if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN)
338 : Control_Surface_ &Control_Surface = Control_Surface_::getInstance();
339 : #endif
340 :
341 : END_CS_NAMESPACE
|