Line data Source code
1 : /* ✔ */ 2 : 3 : #pragma once 4 : 5 : #include <AH/Containers/Updatable.hpp> 6 : #include <AH/Hardware/FilteredAnalog.hpp> 7 : #include <AH/Timing/MillisMicrosTimer.hpp> 8 : #include <Display/DisplayElement.hpp> 9 : #include <Display/DisplayInterface.hpp> 10 : #include <MIDI_Interfaces/MIDI_Interface.hpp> 11 : #include <Settings/SettingsWrapper.hpp> 12 : 13 : BEGIN_CS_NAMESPACE 14 : 15 : using AH::FilteredAnalog; 16 : using AH::NormalUpdatable; 17 : using AH::Timer; 18 : using AH::Updatable; 19 : 20 : /** 21 : * @brief This class ensures initialization, updating, and interaction between 22 : * all other classes, it's the glue that holds everything together. 23 : * 24 : * @ingroup ControlSurfaceModule 25 : */ 26 : class Control_Surface_ : public MIDI_Sender<Control_Surface_>, 27 : public TrueMIDI_SinkSource { 28 : 29 : friend class MIDI_Sender<Control_Surface_>; 30 : 31 : /// @name Singleton boilerplate 32 : /// @{ 33 : 34 : public: 35 : /// Copying is not allowed 36 : Control_Surface_(Control_Surface_ const &) = delete; 37 : /// Copying is not allowed 38 : Control_Surface_ &operator=(Control_Surface_ const &) = delete; 39 : 40 : /// Return the static Control_Surface_ instance (Control_Surface_ is a 41 : /// singleton.) 42 : static Control_Surface_ &getInstance(); 43 : 44 : private: 45 : /// Control_Surface_ is a singleton, so the constructor is private. 46 598 : Control_Surface_() = default; 47 : 48 : /// @} 49 : 50 : public: 51 : /// Initialize the Control_Surface. 52 : /// @see @ref control-surface-purpose 53 : void begin(); 54 : 55 : /// Update all MIDI elements, send MIDI events and read MIDI input. 56 : /// @see @ref control-surface-purpose 57 : void loop(); 58 : 59 : /// Connect Control Surface to the default MIDI interface. 60 : bool connectDefaultMIDI_Interface(); 61 : 62 : /// Disconnect Control Surface from the MIDI interfaces it's connected to. 63 : void disconnectMIDI_Interfaces(); 64 : 65 : /// Update all MIDI interfaces to receive new MIDI events. 66 : void updateMidiInput(); 67 : /// Update all MIDIInputElement%s. 68 : void updateInputs(); 69 : /// Initialize all displays that have at least one display element. 70 : void beginDisplays(); 71 : /// Clear, draw and display all displays that contain display elements that 72 : /// have changed. 73 : void updateDisplays(); 74 : 75 : private: 76 : /// Low-level function for sending a MIDI channel voice message. 77 : void sendChannelMessageImpl(ChannelMessage); 78 : /// Low-level function for sending a MIDI system common message. 79 : void sendSysCommonImpl(SysCommonMessage); 80 : /// Low-level function for sending a system exclusive MIDI message. 81 : void sendSysExImpl(SysExMessage); 82 : /// Low-level function for sending a MIDI real-time message. 83 : void sendRealTimeImpl(RealTimeMessage); 84 : /// Low-level function for sending any buffered outgoing MIDI messages. 85 : /// @todo Implement this in MIDI_Pipe 86 : void sendNowImpl() { /* TODO */ 87 : } 88 : 89 : private: 90 : #if !DISABLE_PIPES 91 : void sinkMIDIfromPipe(ChannelMessage msg) override; 92 : void sinkMIDIfromPipe(SysExMessage msg) override; 93 : void sinkMIDIfromPipe(SysCommonMessage msg) override; 94 : void sinkMIDIfromPipe(RealTimeMessage msg) override; 95 : #else 96 : void sinkMIDIfromPipe(ChannelMessage msg); 97 : void sinkMIDIfromPipe(SysExMessage msg); 98 : void sinkMIDIfromPipe(SysCommonMessage msg); 99 : void sinkMIDIfromPipe(RealTimeMessage msg); 100 : #endif 101 : 102 : private: 103 : /// A timer to know when to refresh the displays. 104 : Timer<micros> displayTimer = {1000000UL / MAX_FPS}; 105 : 106 : public: 107 : /// @name MIDI Input Callbacks 108 : /// @{ 109 : 110 : /// Callback function type for channel messages. Return true if handling is 111 : /// done in the user-provided callback, false if `Control_Surface` 112 : /// should handle the message. 113 : using ChannelMessageCallback = bool (*)(ChannelMessage); 114 : /// Callback function type for SysEx messages. Return true if handling is 115 : /// done in the user-provided callback, false if `Control_Surface` 116 : /// should handle the message. 117 : using SysExMessageCallback = bool (*)(SysExMessage); 118 : /// Callback function type for System Common messages. Return true if 119 : /// handling is done in the user-provided callback, false if 120 : /// `Control_Surface` should handle the message. 121 : using SysCommonMessageCallback = bool (*)(SysCommonMessage); 122 : /// Callback function type for Real-Time messages. Return true if handling 123 : /// is done in the user-provided callback, false if `Control_Surface` 124 : /// should handle the message. 125 : using RealTimeMessageCallback = bool (*)(RealTimeMessage); 126 : 127 : /// Set the MIDI input callbacks. 128 : void 129 : setMIDIInputCallbacks(ChannelMessageCallback channelMessageCallback, 130 : SysExMessageCallback sysExMessageCallback, 131 : SysCommonMessageCallback sysCommonMessageCallback, 132 : RealTimeMessageCallback realTimeMessageCallback) { 133 : this->channelMessageCallback = channelMessageCallback; 134 : this->sysExMessageCallback = sysExMessageCallback; 135 : this->sysCommonMessageCallback = sysCommonMessageCallback; 136 : this->realTimeMessageCallback = realTimeMessageCallback; 137 : } 138 : 139 : /// @} 140 : 141 : private: 142 : ChannelMessageCallback channelMessageCallback = nullptr; 143 : SysExMessageCallback sysExMessageCallback = nullptr; 144 : SysCommonMessageCallback sysCommonMessageCallback = nullptr; 145 : RealTimeMessageCallback realTimeMessageCallback = nullptr; 146 : #if !DISABLE_PIPES 147 : MIDI_Pipe inpipe, outpipe; 148 : #endif 149 : }; 150 : 151 : #if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN) 152 : /// A predefined instance of the Control Surface to use in the Arduino sketches. 153 : extern Control_Surface_ &Control_Surface; 154 : #else 155 : // This is not a clean solution, but it's the only way to get the linker to 156 : // optimize away all Control Surface-related code if the `Control_Surface` 157 : // instance is never used. 158 : // Even if it isn't used, and even though it's a global, the compiler has to 159 : // generate the constructor and destructor, which pulls in variables and vtables 160 : // from throughout the library, using a significant amount of memory. 161 : // By using a macro here, Control_Surface is only constructed (and destructed) 162 : // if it is used in user code. 163 : #define Control_Surface (Control_Surface_::getInstance()) 164 : #endif 165 : 166 : END_CS_NAMESPACE