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 1 : 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 : /** 41 : * @brief Return the static Control_Surface_ instance. 42 : * (Control_Surface_ is a singleton.) 43 : */ 44 : static Control_Surface_ &getInstance(); 45 : 46 : private: 47 : /** 48 : * @brief Control_Surface_ is a singleton, so the constructor is private. 49 : */ 50 2 : Control_Surface_() = default; 51 : 52 : /// @} 53 : 54 : public: 55 : /** 56 : * @brief Initialize the Control_Surface. 57 : */ 58 : void begin(); 59 : 60 : /** 61 : * @brief Update all MIDI elements, send MIDI events and read MIDI input. 62 : */ 63 : void loop(); 64 : 65 : /** 66 : * @brief Connect Control Surface to the default MIDI interface. 67 : */ 68 : bool connectDefaultMIDI_Interface(); 69 : 70 : /** 71 : * @brief Disconnect Control Surface from the MIDI interfaces it's 72 : * connected to. 73 : */ 74 : void disconnectMIDI_Interfaces(); 75 : 76 : /** 77 : * @brief Get a reference to the MIDI sender. 78 : * 79 : * @deprecated Use `Control_Surface.send(...)` directly instead of 80 : * `Control_Surface.MIDI().send(...)`. 81 : */ 82 : [[deprecated("Use Control_Surface.send(...) directly, instead of " 83 : "Control_Surface.MIDI().send(...)")]] // 84 : MIDI_Sender<Control_Surface_> & 85 : MIDI() { 86 : return *this; 87 : } 88 : /** 89 : * @brief Update all MIDI interfaces to receive new MIDI events. 90 : */ 91 : void updateMidiInput(); 92 : 93 : /** 94 : * @brief Update all MIDIInputElement%s. 95 : */ 96 : void updateInputs(); 97 : 98 : /** 99 : * @brief Clear, draw and display all displays. 100 : */ 101 : void updateDisplays(); 102 : 103 : private: 104 : /** 105 : * @brief Low-level function for sending a 3-byte MIDI message. 106 : */ 107 : void sendImpl(uint8_t header, uint8_t d1, uint8_t d2, uint8_t cn); 108 : /** 109 : * @brief Low-level function for sending a 2-byte MIDI message. 110 : */ 111 : void sendImpl(uint8_t header, uint8_t d1, uint8_t cn); 112 : 113 : /** 114 : * @brief Low-level function for sending a system exclusive MIDI message. 115 : */ 116 : void sendImpl(const uint8_t *data, size_t length, uint8_t cn); 117 : 118 : /** 119 : * @brief Low-level function for sending a single-byte MIDI message. 120 : */ 121 : void sendImpl(uint8_t rt, uint8_t cn); 122 : 123 : private: 124 : void sinkMIDIfromPipe(ChannelMessage msg) override; 125 : void sinkMIDIfromPipe(SysExMessage msg) override; 126 : void sinkMIDIfromPipe(RealTimeMessage msg) override; 127 : 128 : private: 129 : /// A timer to know when to update the analog inputs. 130 1 : Timer<micros> potentiometerTimer = {AH::FILTERED_INPUT_UPDATE_INTERVAL}; 131 : /// A timer to know when to refresh the displays. 132 1 : Timer<micros> displayTimer = {1000000UL / MAX_FPS}; 133 : 134 : public: 135 : /// @name MIDI Input Callbacks 136 : /// @{ 137 : 138 : /// Callback function type for channel messages. Return true if handling is 139 : /// done in the user-provided callback, false if `Control_Surface` 140 : /// should handle the message. 141 : using ChannelMessageCallback = bool (*)(ChannelMessage); 142 : /// Callback function type for SysEx messages. Return true if handling is 143 : /// done in the user-provided callback, false if `Control_Surface` 144 : /// should handle the message. 145 : using SysExMessageCallback = bool (*)(SysExMessage); 146 : /// Callback function type for Real-Time messages. Return true if handling 147 : /// is done in the user-provided callback, false if `Control_Surface` 148 : /// should handle the message. 149 : using RealTimeMessageCallback = bool (*)(RealTimeMessage); 150 : 151 : /// Set the MIDI input callbacks. 152 : void 153 : setMIDIInputCallbacks(ChannelMessageCallback channelMessageCallback, 154 : SysExMessageCallback sysExMessageCallback, 155 : RealTimeMessageCallback realTimeMessageCallback) { 156 : this->channelMessageCallback = channelMessageCallback; 157 : this->sysExMessageCallback = sysExMessageCallback; 158 : this->realTimeMessageCallback = realTimeMessageCallback; 159 : } 160 : 161 : /// @} 162 : 163 : private: 164 1 : ChannelMessageCallback channelMessageCallback = nullptr; 165 1 : SysExMessageCallback sysExMessageCallback = nullptr; 166 1 : RealTimeMessageCallback realTimeMessageCallback = nullptr; 167 : MIDI_Pipe inpipe, outpipe; 168 : }; 169 : 170 : /// A predefined instance of the Control Surface to use in the Arduino sketches. 171 : extern Control_Surface_ &Control_Surface; 172 : 173 : END_CS_NAMESPACE