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