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 587 : Control_Surface_() = default; 47 : 48 : /// @} 49 : 50 : public: 51 : /// Initialize the Control_Surface. 52 : void begin(); 53 : 54 : /// Update all MIDI elements, send MIDI events and read MIDI input. 55 : void loop(); 56 : 57 : /// Connect Control Surface to the default MIDI interface. 58 : bool connectDefaultMIDI_Interface(); 59 : 60 : /// Disconnect Control Surface from the MIDI interfaces it's connected to. 61 : void disconnectMIDI_Interfaces(); 62 : 63 : /// Update all MIDI interfaces to receive new MIDI events. 64 : void updateMidiInput(); 65 : /// Update all MIDIInputElement%s. 66 : void updateInputs(); 67 : /// Initialize all displays that have at least one display element. 68 : void beginDisplays(); 69 : /// Clear, draw and display all displays that contain display elements that 70 : /// have changed. 71 : void updateDisplays(); 72 : 73 : private: 74 : /// Low-level function for sending a MIDI channel voice message. 75 : void sendChannelMessageImpl(ChannelMessage); 76 : /// Low-level function for sending a MIDI system common message. 77 : void sendSysCommonImpl(SysCommonMessage); 78 : /// Low-level function for sending a system exclusive MIDI message. 79 : void sendSysExImpl(SysExMessage); 80 : /// Low-level function for sending a MIDI real-time message. 81 : void sendRealTimeImpl(RealTimeMessage); 82 : /// Low-level function for sending any buffered outgoing MIDI messages. 83 : /// @todo Implement this in MIDI_Pipe 84 : void sendNowImpl() { /* TODO */ } 85 : 86 : private: 87 : #if !DISABLE_PIPES 88 : void sinkMIDIfromPipe(ChannelMessage msg) override; 89 : void sinkMIDIfromPipe(SysExMessage msg) override; 90 : void sinkMIDIfromPipe(SysCommonMessage msg) override; 91 : void sinkMIDIfromPipe(RealTimeMessage msg) override; 92 : #else 93 : void sinkMIDIfromPipe(ChannelMessage msg); 94 : void sinkMIDIfromPipe(SysExMessage msg); 95 : void sinkMIDIfromPipe(SysCommonMessage msg); 96 : void sinkMIDIfromPipe(RealTimeMessage msg); 97 : #endif 98 : 99 : private: 100 : /// A timer to know when to refresh the displays. 101 : Timer<micros> displayTimer = {1000000UL / MAX_FPS}; 102 : 103 : public: 104 : /// @name MIDI Input Callbacks 105 : /// @{ 106 : 107 : /// Callback function type for channel messages. Return true if handling is 108 : /// done in the user-provided callback, false if `Control_Surface` 109 : /// should handle the message. 110 : using ChannelMessageCallback = bool (*)(ChannelMessage); 111 : /// Callback function type for SysEx messages. Return true if handling is 112 : /// done in the user-provided callback, false if `Control_Surface` 113 : /// should handle the message. 114 : using SysExMessageCallback = bool (*)(SysExMessage); 115 : /// Callback function type for System Common messages. Return true if 116 : /// handling is done in the user-provided callback, false if 117 : /// `Control_Surface` should handle the message. 118 : using SysCommonMessageCallback = bool (*)(SysCommonMessage); 119 : /// Callback function type for Real-Time messages. Return true if handling 120 : /// is done in the user-provided callback, false if `Control_Surface` 121 : /// should handle the message. 122 : using RealTimeMessageCallback = bool (*)(RealTimeMessage); 123 : 124 : /// Set the MIDI input callbacks. 125 : void 126 : setMIDIInputCallbacks(ChannelMessageCallback channelMessageCallback, 127 : SysExMessageCallback sysExMessageCallback, 128 : SysCommonMessageCallback sysCommonMessageCallback, 129 : RealTimeMessageCallback realTimeMessageCallback) { 130 : this->channelMessageCallback = channelMessageCallback; 131 : this->sysExMessageCallback = sysExMessageCallback; 132 : this->sysCommonMessageCallback = sysCommonMessageCallback; 133 : this->realTimeMessageCallback = realTimeMessageCallback; 134 : } 135 : 136 : /// @} 137 : 138 : private: 139 : ChannelMessageCallback channelMessageCallback = nullptr; 140 : SysExMessageCallback sysExMessageCallback = nullptr; 141 : SysCommonMessageCallback sysCommonMessageCallback = nullptr; 142 : RealTimeMessageCallback realTimeMessageCallback = nullptr; 143 : #if !DISABLE_PIPES 144 : MIDI_Pipe inpipe, outpipe; 145 : #endif 146 : }; 147 : 148 : #if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN) 149 : /// A predefined instance of the Control Surface to use in the Arduino sketches. 150 : extern Control_Surface_ &Control_Surface; 151 : #else 152 : // This is not a clean solution, but it's the only way to get the linker to 153 : // optimize away all Control Surface-related code if the `Control_Surface` 154 : // instance is never used. 155 : // Even if it isn't used, and even though it's a global, the compiler has to 156 : // generate the constructor and destructor, which pulls in variables and vtables 157 : // from throughout the library, using a significant amount of memory. 158 : // By using a macro here, Control_Surface is only constructed (and destructed) 159 : // if it is used in user code. 160 : #define Control_Surface (Control_Surface_::getInstance()) 161 : #endif 162 : 163 : END_CS_NAMESPACE