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
|