Line data Source code
1 : #pragma once
2 :
3 : #include <AH/STL/utility> // std::forward
4 : #include <Banks/BankableAddresses.hpp>
5 : #include <Def/Def.hpp>
6 : #include <Def/TypeTraits.hpp>
7 : #include <MIDI_Outputs/Abstract/EncoderState.hpp>
8 : #include <MIDI_Outputs/Abstract/MIDIOutputElement.hpp>
9 :
10 : #ifdef ARDUINO
11 : #include <Submodules/Encoder/AHEncoder.hpp>
12 : #else
13 : #include <Encoder.h> // Mock
14 : #endif
15 :
16 : BEGIN_CS_NAMESPACE
17 :
18 : namespace Bankable {
19 :
20 : /**
21 : * @brief An abstract class for rotary encoders that send absolute MIDI
22 : * events.
23 : */
24 : template <class Enc, uint8_t NumBanks, class BankAddress, class Sender>
25 : class GenericMIDIAbsoluteEncoder : public MIDIOutputElement {
26 : public:
27 4 : GenericMIDIAbsoluteEncoder(const BankAddress &address, Enc &&encoder,
28 : int16_t speedMultiply, uint8_t pulsesPerStep,
29 : const Sender &sender)
30 4 : : encoder(std::forward<Enc>(encoder)), address(address),
31 8 : encstate(speedMultiply, pulsesPerStep), sender(sender) {}
32 :
33 0 : void begin() override { begin_if_possible(encoder); }
34 :
35 0 : void update() override {
36 0 : auto encval = encoder.read();
37 0 : if (int16_t delta = encstate.update(encval)) {
38 0 : address.lock();
39 0 : int16_t oldValue = values[address.getSelection()];
40 0 : int16_t newValue = oldValue + delta;
41 0 : newValue = constrain(newValue, 0, maxValue);
42 0 : if (oldValue != newValue) {
43 0 : values[address.getSelection()] = newValue;
44 0 : forcedUpdate();
45 : }
46 0 : address.unlock();
47 : }
48 0 : }
49 :
50 : /// Send the current value over MIDI, even if the position of the encoder
51 : /// didn't change.
52 0 : void forcedUpdate() {
53 0 : sender.send(values[address.getSelection()], address.getActiveAddress());
54 0 : }
55 : void forcedUpdate(setting_t bank) {
56 : sender.send(values[bank], address.getActiveAddress(bank));
57 : }
58 :
59 : /**
60 : * @brief Get the absolute value of the encoder in the given bank.
61 : */
62 : uint16_t getValue(setting_t bank) const { return values[bank]; }
63 : /**
64 : * @brief Get the absolute value of the encoder in the active bank.
65 : */
66 : uint16_t getValue() const { return getValue(address.getSelection()); }
67 :
68 : /**
69 : * @brief Set the absolute value of the encoder in the given bank.
70 : */
71 : void setValue(uint16_t value, setting_t bank) { values[bank] = value; }
72 : /**
73 : * @brief Set the absolute value of the encoder in the active bank.
74 : */
75 : void setValue(uint16_t value) { setValue(value, address.getSelection()); }
76 :
77 : /// Get the maximum possible value that can be returned by @ref getValue.
78 : static int16_t getMaxValue() { return maxValue; }
79 :
80 : void setSpeedMultiply(int16_t speedMultiply) {
81 : encstate.setSpeedMultiply(speedMultiply);
82 : }
83 : int16_t getSpeedMultiply() const { return encstate.getSpeedMultiply(); }
84 :
85 : int16_t resetPositionOffset() {
86 : auto encval = encoder.read();
87 : return encstate.update(encval);
88 : }
89 :
90 : protected:
91 : Enc encoder;
92 : BankAddress address;
93 : Array<int16_t, NumBanks> values = {{}};
94 : EncoderState<decltype(encoder.read())> encstate;
95 :
96 : constexpr static int16_t maxValue = uint16_t(1u << Sender::precision()) - 1;
97 :
98 : public:
99 : Sender sender;
100 : };
101 :
102 : template <uint8_t NumBanks, class BankAddress, class Sender>
103 : using MIDIAbsoluteEncoder =
104 : GenericMIDIAbsoluteEncoder<AHEncoder, NumBanks, BankAddress, Sender>;
105 :
106 : template <uint8_t NumBanks, class BankAddress, class Sender>
107 : using BorrowedMIDIAbsoluteEncoder =
108 : GenericMIDIAbsoluteEncoder<AHEncoder &, NumBanks, BankAddress, Sender>;
109 :
110 : } // namespace Bankable
111 :
112 : END_CS_NAMESPACE
|