LCOV - code coverage report
Current view: top level - src/MIDI_Outputs/Abstract - MIDIAbsoluteEncoder.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 94.1 % 17 16
Test Date: 2026-06-06 17:44:35 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta