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