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