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 584 : 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 : void sinkMIDIfromPipe(ChannelMessage msg) override; 88 : void sinkMIDIfromPipe(SysExMessage msg) override; 89 : void sinkMIDIfromPipe(SysCommonMessage msg) override; 90 : void sinkMIDIfromPipe(RealTimeMessage msg) override; 91 : 92 : private: 93 : /// A timer to know when to refresh the displays. 94 : Timer<micros> displayTimer = {1000000UL / MAX_FPS}; 95 : 96 : public: 97 : /// @name MIDI Input Callbacks 98 : /// @{ 99 : 100 : /// Callback function type for channel messages. Return true if handling is 101 : /// done in the user-provided callback, false if `Control_Surface` 102 : /// should handle the message. 103 : using ChannelMessageCallback = bool (*)(ChannelMessage); 104 : /// Callback function type for SysEx messages. Return true if handling is 105 : /// done in the user-provided callback, false if `Control_Surface` 106 : /// should handle the message. 107 : using SysExMessageCallback = bool (*)(SysExMessage); 108 : /// Callback function type for System Common messages. Return true if 109 : /// handling is done in the user-provided callback, false if 110 : /// `Control_Surface` should handle the message. 111 : using SysCommonMessageCallback = bool (*)(SysCommonMessage); 112 : /// Callback function type for Real-Time messages. Return true if handling 113 : /// is done in the user-provided callback, false if `Control_Surface` 114 : /// should handle the message. 115 : using RealTimeMessageCallback = bool (*)(RealTimeMessage); 116 : 117 : /// Set the MIDI input callbacks. 118 : void 119 : setMIDIInputCallbacks(ChannelMessageCallback channelMessageCallback, 120 : SysExMessageCallback sysExMessageCallback, 121 : SysCommonMessageCallback sysCommonMessageCallback, 122 : RealTimeMessageCallback realTimeMessageCallback) { 123 : this->channelMessageCallback = channelMessageCallback; 124 : this->sysExMessageCallback = sysExMessageCallback; 125 : this->sysCommonMessageCallback = sysCommonMessageCallback; 126 : this->realTimeMessageCallback = realTimeMessageCallback; 127 : } 128 : 129 : /// @} 130 : 131 : private: 132 : ChannelMessageCallback channelMessageCallback = nullptr; 133 : SysExMessageCallback sysExMessageCallback = nullptr; 134 : SysCommonMessageCallback sysCommonMessageCallback = nullptr; 135 : RealTimeMessageCallback realTimeMessageCallback = nullptr; 136 : MIDI_Pipe inpipe, outpipe; 137 : }; 138 : 139 : #if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN) 140 : /// A predefined instance of the Control Surface to use in the Arduino sketches. 141 : extern Control_Surface_ &Control_Surface; 142 : #else 143 : // This is not a clean solution, but it's the only way to get the linker to 144 : // optimize away all Control Surface-related code if the `Control_Surface` 145 : // instance is never used. 146 : // Even if it isn't used, and even though it's a global, the compiler has to 147 : // generate the constructor and destructor, which pulls in variables and vtables 148 : // from throughout the library, using a significant amount of memory. 149 : // By using a macro here, Control_Surface is only constructed (and destructed) 150 : // if it is used in user code. 151 : #define Control_Surface (Control_Surface_::getInstance()) 152 : #endif 153 : 154 : END_CS_NAMESPACE