Line data Source code
1 : #pragma once 2 : 3 : #include <AH/STL/type_traits> // std::make_signed 4 : #include <AH/STL/utility> // std::forward 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 : /** 21 : * @brief An abstract class for rotary encoders that send absolute MIDI 22 : * events. 23 : */ 24 : template <class Enc, class Sender> 25 : class GenericMIDIAbsoluteEncoder : public MIDIOutputElement { 26 : public: 27 1 : GenericMIDIAbsoluteEncoder(Enc &&encoder, MIDIAddress address, 28 : int16_t speedMultiply, uint8_t pulsesPerStep, 29 : const Sender &sender) 30 1 : : encoder(std::forward<Enc>(encoder)), address(address), 31 2 : encstate(speedMultiply, pulsesPerStep), sender(sender) {} 32 : 33 0 : void begin() override { begin_if_possible(encoder); } 34 : 35 1 : void update() override { 36 1 : auto encval = encoder.read(); 37 1 : if (int16_t delta = encstate.update(encval)) { 38 1 : int16_t oldValue = value; 39 1 : int16_t newValue = oldValue + delta; 40 1 : newValue = constrain(newValue, 0, maxValue); 41 1 : if (oldValue != newValue) { 42 1 : value = newValue; 43 1 : forcedUpdate(); 44 : } 45 : } 46 1 : } 47 : 48 : /// Send the current value over MIDI, even if the position of the encoder 49 : /// didn't change. 50 1 : void forcedUpdate() { sender.send(value, address); } 51 : 52 : /** 53 : * @brief Get the absolute value of the encoder. 54 : */ 55 1 : uint16_t getValue() const { return value; } 56 : 57 : /** 58 : * @brief Set the absolute value of the encoder. 59 : */ 60 1 : void setValue(uint16_t value) { this->value = value; } 61 : 62 : /// Get the maximum possible value that can be returned by @ref getValue. 63 : static int16_t getMaxValue() { return maxValue; } 64 : 65 : void setSpeedMultiply(int16_t speedMultiply) { 66 : encstate.setSpeedMultiply(speedMultiply); 67 : } 68 : int16_t getSpeedMultiply() const { return encstate.getSpeedMultiply(); } 69 : 70 : /// Get the MIDI address. 71 : MIDIAddress getAddress() const { return this->address; } 72 : /// Set the MIDI address. 73 : void setAddress(MIDIAddress address) { this->address = address; } 74 : 75 : private: 76 : Enc encoder; 77 : MIDIAddress address; 78 : int16_t value = 0; 79 : EncoderState<decltype(encoder.read())> encstate; 80 : 81 : constexpr static int16_t maxValue = uint16_t(1u << Sender::precision()) - 1; 82 : 83 : public: 84 : Sender sender; 85 : }; 86 : 87 : template <class Sender> 88 : using MIDIAbsoluteEncoder = GenericMIDIAbsoluteEncoder<AHEncoder, Sender>; 89 : 90 : template <class Sender> 91 : using BorrowedMIDIAbsoluteEncoder = 92 : GenericMIDIAbsoluteEncoder<AHEncoder &, Sender>; 93 : 94 : END_CS_NAMESPACE 95 : 96 : AH_DIAGNOSTIC_POP()