Control Surface master
MIDI Control Surface library for Arduino
VPotRing.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <AH/STL/algorithm>
7
9
10namespace MCU {
11
14struct VPotState {
16 VPotState(uint8_t value = 0) : value(value) {}
17
18 uint8_t value;
19
20 bool update(uint8_t data) {
21 data = sanitizeData(data);
22 bool changed = data != this->value;
23 this->value = data;
24 return changed;
25 }
26
28 enum Mode {
31 Wrap = 2,
32 Spread = 3,
33 };
34
37
39 uint8_t getPosition() const { return value & 0x0F; }
41 bool getCenterLed() const { return value & 0x40; }
43 Mode getMode() const { return static_cast<Mode>((value & 0x30) >> 4); }
44
46 uint8_t getStartOn() const {
47 int8_t position = getPosition();
48 if (position == 0)
49 return 0;
50 int8_t value = position - 1;
51 switch (getMode()) {
52 case SingleDot: return value;
53 case BoostCut: return std::min(+value, 5);
54 case Wrap: return 0;
55 case Spread: return std::max(5 - value, 0);
56 default: return 0;
57 }
58 }
59
61 uint8_t getStartOff() const {
62 uint8_t value = getPosition();
63 switch (getMode()) {
64 case SingleDot: return value;
65 case BoostCut: return std::max(+value, 6);
66 case Wrap: return value;
67 case Spread: return std::min(5 + value, 11);
68 default: return 0;
69 }
70 }
71
73
76 static uint8_t sanitizeData(uint8_t data) {
77 // Maximum valid position value is 0xB.
78 return (data & 0x0F) <= 0x0B ? data : ((data & 0xF0) | 0x0B);
79 }
80};
81
82// -------------------------------------------------------------------------- //
83
118 VPotMatcher(uint8_t track, MIDIChannelCable channelCN)
119 : TwoByteMIDIMatcher({track + 0x30 - 1, channelCN}) {}
120};
121
126template <uint8_t BankSize>
141 MIDIChannelCable channelCN)
143 {track + 0x30 - 1, channelCN}) {}
144};
145
146// -------------------------------------------------------------------------- //
147
155 : public MatchingMIDIInputElement<MIDIMessageType::CONTROL_CHANGE,
156 VPotMatcher>,
158 public:
160 using Parent
162
172 VPotRing(uint8_t track, MIDIChannelCable channelCN = CHANNEL_1)
173 : Parent({track, channelCN}) {}
174
175 protected:
176 bool handleUpdateImpl(typename Matcher::Result match) {
177 return state.update(match.value);
178 }
179
180 void handleUpdate(typename Matcher::Result match) override {
181 dirty |= handleUpdateImpl(match);
182 }
183
184 public:
187
189 VPotState getState() const { return state; }
190
192 uint8_t getPosition() const { return state.getPosition(); }
194 bool getCenterLed() const override { return state.getCenterLed(); }
196 VPotState::Mode getMode() const { return state.getMode(); }
197
199 uint8_t getStartOn() const override { return state.getStartOn(); }
201 uint8_t getStartOff() const override { return state.getStartOff(); }
202
204
206 void reset() override {
207 if (!ignoreReset) {
208 state = {};
209 dirty = true;
210 }
211 }
212
213 private:
215
216 public:
220 bool ignoreReset = true;
221};
222
223// -------------------------------------------------------------------------- //
224
225namespace Bankable {
226
236template <uint8_t BankSize>
238 : public BankableMatchingMIDIInputElement<MIDIMessageType::CONTROL_CHANGE,
239 BankableVPotMatcher<BankSize>>,
241 public:
243 using Parent
245 Matcher>;
258 VPotRing(BankConfig<BankSize> config, uint8_t track,
259 MIDIChannelCable channelCN = CHANNEL_1)
260 : Parent({config, track, channelCN}) {}
261
262 protected:
263 bool handleUpdateImpl(typename Matcher::Result match) {
264 return states[match.bankIndex].update(match.value) &&
265 match.bankIndex == this->getActiveBank();
266 // Only mark dirty if the value of the active bank changed
267 }
268
269 void handleUpdate(typename Matcher::Result match) override {
270 dirty |= handleUpdateImpl(match);
271 }
272
273 public:
276
278 VPotState getState(uint8_t bank) const { return states[bank]; }
279
282 uint8_t getPosition(uint8_t bank) const {
283 return getState(bank).getPosition();
284 }
287 bool getCenterLed(uint8_t bank) const {
288 return getState(bank).getCenterLed();
289 }
292 VPotState::Mode getMode(uint8_t bank) const {
293 return getState(bank).getMode();
294 }
295
298 uint8_t getStartOn(uint8_t bank) const {
299 return getState(bank).getStartOn();
300 }
303 uint8_t getStartOff(uint8_t bank) const {
304 return getState(bank).getStartOff();
305 }
306
308 VPotState getState() const { return getState(this->getActiveBank()); }
309
312 uint8_t getPosition() const { return getPosition(this->getActiveBank()); }
315 bool getCenterLed() const override {
316 return getCenterLed(this->getActiveBank());
317 }
320 VPotState::Mode getMode() const { return getMode(this->getActiveBank()); }
321
324 uint8_t getStartOn() const override {
325 return getStartOn(this->getActiveBank());
326 }
329 uint8_t getStartOff() const override {
330 return getStartOff(this->getActiveBank());
331 }
332
334
336 void reset() override {
337 if (!ignoreReset) {
338 states = {{}};
339 dirty = true;
340 }
341 }
342
343 protected:
344 void onBankSettingChange() override { dirty = true; }
345
346 private:
348
349 public:
353 bool ignoreReset = true;
354};
355
356} // namespace Bankable
357
358} // namespace MCU
359
constexpr Channel CHANNEL_1
Definition: Channel.hpp:118
Wrap
An enumeration to set the behavior of selectors that are incremented (decremented) beyond their maxim...
Definition: Selector.hpp:14
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Similar to MatchingMIDIInputElement, but for Bankable MIDI Input Elements.
A MIDI input element that represents a Mackie Control Universal VPot ring.
Definition: VPotRing.hpp:240
VPotRing(BankConfig< BankSize > config, uint8_t track, MIDIChannelCable channelCN=CHANNEL_1)
Constructor.
Definition: VPotRing.hpp:258
VPotState::Mode getMode() const
Return the mode of the V-Pot ring.
Definition: VPotRing.hpp:320
bool getCenterLed(uint8_t bank) const
Return the status of the center LED of the V-Pot ring.
Definition: VPotRing.hpp:287
uint8_t getStartOff(uint8_t bank) const
Get the first segment that should be off.
Definition: VPotRing.hpp:303
VPotState::Mode getMode(uint8_t bank) const
Return the mode of the V-Pot ring.
Definition: VPotRing.hpp:292
bool ignoreReset
Don't reset the state when calling the reset method.
Definition: VPotRing.hpp:353
uint8_t getStartOff() const override
Get the first segment that should be off.
Definition: VPotRing.hpp:329
void onBankSettingChange() override
A function to be executed each time the bank setting changes.
Definition: VPotRing.hpp:344
uint8_t getPosition() const
Return the position of the V-Pot ring. [0, 11].
Definition: VPotRing.hpp:312
VPotState getState() const
Get the full state of the VPot ring. (For the active bank.)
Definition: VPotRing.hpp:308
bool handleUpdateImpl(typename Matcher::Result match)
Definition: VPotRing.hpp:263
uint8_t getStartOn() const override
Get the first segment that should be on.
Definition: VPotRing.hpp:324
VPotState getState(uint8_t bank) const
Get the full state of the VPot ring. (For the given bank.)
Definition: VPotRing.hpp:278
uint8_t getPosition(uint8_t bank) const
Return the position of the V-Pot ring. [0, 11].
Definition: VPotRing.hpp:282
AH::Array< VPotState, BankSize > states
Definition: VPotRing.hpp:347
void handleUpdate(typename Matcher::Result match) override
Definition: VPotRing.hpp:269
void reset() override
Reset all states to zero.
Definition: VPotRing.hpp:336
uint8_t getStartOn(uint8_t bank) const
Get the first segment that should be on.
Definition: VPotRing.hpp:298
bool getCenterLed() const override
Return the status of the center LED of the V-Pot ring.
Definition: VPotRing.hpp:315
A MIDI input element that represents a Mackie Control Universal VPot ring.
Definition: VPotRing.hpp:157
VPotState::Mode getMode() const
Return the mode of the V-Pot ring.
Definition: VPotRing.hpp:196
bool ignoreReset
Don't reset the state when calling the reset method.
Definition: VPotRing.hpp:220
uint8_t getStartOff() const override
Get the first segment that should be off.
Definition: VPotRing.hpp:201
uint8_t getPosition() const
Return the position of the V-Pot ring. [0, 11].
Definition: VPotRing.hpp:192
VPotState getState() const
Get the full state of the VPot ring.
Definition: VPotRing.hpp:189
bool handleUpdateImpl(typename Matcher::Result match)
Definition: VPotRing.hpp:176
uint8_t getStartOn() const override
Get the first segment that should be on.
Definition: VPotRing.hpp:199
VPotRing(uint8_t track, MIDIChannelCable channelCN=CHANNEL_1)
Constructor.
Definition: VPotRing.hpp:172
void handleUpdate(typename Matcher::Result match) override
Definition: VPotRing.hpp:180
VPotState state
Definition: VPotRing.hpp:214
void reset() override
Reset the state to zero.
Definition: VPotRing.hpp:206
bool getCenterLed() const override
Return the status of the center LED of the V-Pot ring.
Definition: VPotRing.hpp:194
A class for saving a MIDI channel and cable number.
Definition: MIDIAddress.hpp:24
The MIDIInputElement base class is very general: you give it a MIDI message, and it calls the updateW...
constexpr auto min(const T &a, const U &b) -> decltype(b< a ? b :a)
Return the smaller of two numbers/objects.
Definition: MinMaxFix.hpp:15
constexpr auto max(const T &a, const U &b) -> decltype(a< b ? b :a)
Return the larger of two numbers/objects.
Definition: MinMaxFix.hpp:22
A namespace for MIDI elements that can be added to a Bank, to change their address or channel.
An array wrapper for easy copying, comparing, and iterating.
Definition: Array.hpp:36
Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control Change, Key Pressure.
BaseBankConfig< BankSize > config
MIDI Input matcher for Mackie Control Universal VPot LED rings with bank support.
Definition: VPotRing.hpp:127
BankableVPotMatcher(BankConfig< BankSize > config, uint8_t track, MIDIChannelCable channelCN)
Constructor.
Definition: VPotRing.hpp:140
MIDI Input matcher for Mackie Control Universal VPot LED rings.
Definition: VPotRing.hpp:108
VPotMatcher(uint8_t track, MIDIChannelCable channelCN)
Constructor.
Definition: VPotRing.hpp:118
Struct that keeps track of the value and overload indicator of a Mackie Control Universal VPot LED ri...
Definition: VPotRing.hpp:14
Mode getMode() const
Return the mode of the V-Pot ring.
Definition: VPotRing.hpp:43
uint8_t getStartOff() const
Get the first segment that should be off.
Definition: VPotRing.hpp:61
uint8_t getStartOn() const
Get the first segment that should be on.
Definition: VPotRing.hpp:46
bool getCenterLed() const
Return the status of the center LED of the V-Pot ring.
Definition: VPotRing.hpp:41
Mode
Determines how the VPot value is displayed using the LEDs.
Definition: VPotRing.hpp:28
@ SingleDot
Single dot.
Definition: VPotRing.hpp:29
@ BoostCut
Boost/Cut.
Definition: VPotRing.hpp:30
@ Spread
Spread.
Definition: VPotRing.hpp:32
uint8_t value
The value representing the VPot position, mode and LED.
Definition: VPotRing.hpp:18
uint8_t getPosition() const
Return the position of the V-Pot ring. [0, 11].
Definition: VPotRing.hpp:39
static uint8_t sanitizeData(uint8_t data)
Make sure that the received value is valid and will not result in array out of bounds conditions.
Definition: VPotRing.hpp:76
bool update(uint8_t data)
Definition: VPotRing.hpp:20
VPotState(uint8_t value=0)
Constructor.
Definition: VPotRing.hpp:16
Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control Change, Key Pressure (but n...