Control Surface new-input
MIDI Control Surface library for Arduino
Abstract/MIDIRotaryEncoder.hpp
Go to the documentation of this file.
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>
8 
9 #ifdef ARDUINO
11 #else
12 #include <Encoder.h> // Mock
13 #endif
14 
16 
18 
22 template <class Enc, class Sender>
24  public:
30  GenericMIDIRotaryEncoder(Enc &&encoder, MIDIAddress address,
31  int16_t speedMultiply, uint8_t pulsesPerStep,
32  const Sender &sender)
33  : encoder(std::forward<Enc>(encoder)), address(address),
34  speedMultiply(speedMultiply), pulsesPerStep(pulsesPerStep),
35  sender(sender) {}
36 
37  void begin() override { begin_if_possible(encoder); }
38 
39  void update() override {
40  Enc_t encval = encoder.read();
41  // If Enc_t is an unsigned type, integer overflow is well-defined, which
42  // is what we want when Enc_t is small and expected to overflow.
43  // However, we need it to be signed because we're interested in the
44  // delta.
45  Enc_t uDelta = encval - deltaOffset;
46  if (uDelta) {
47  int16_t delta = SignedEnc_t(uDelta);
48  // Assumption: delta and speedMultiply are relatively small, so
49  // multiplication probably won't overflow.
50  int16_t multipliedDelta = delta * speedMultiply + remainder;
51  int16_t scaledDelta = multipliedDelta / pulsesPerStep;
52  remainder = multipliedDelta % pulsesPerStep;
53 
54  if (scaledDelta)
55  sender.send(scaledDelta, address);
56  deltaOffset += uDelta;
57  }
58  }
59 
60  void setSpeedMultiply(int16_t speedMultiply) {
61  // TODO: Is this correct? Is it necessary? What with negative speedMult?
62  remainder = remainder * speedMultiply / this->speedMultiply;
63  this->speedMultiply = speedMultiply;
64  }
65  int16_t getSpeedMultiply() const { return this->speedMultiply; }
66 
67  private:
68  Enc encoder;
70  int16_t speedMultiply;
71  uint8_t pulsesPerStep;
72  int16_t remainder = 0;
73  using Enc_t = decltype(encoder.read());
74  using SignedEnc_t = typename std::make_signed<Enc_t>::type;
75  Enc_t deltaOffset = 0;
76 
77  public:
78  Sender sender;
79 };
80 
81 template <class Sender>
83 
84 template <class Sender>
86 
88 
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
std::enable_if< has_method_begin< T >::value >::type begin_if_possible(T &t)
Calls the begin() method of t if that method exists.
Definition: TypeTraits.hpp:23
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:173
An abstract class for rotary encoders that send MIDI events.
void setSpeedMultiply(int16_t speedMultiply)
void update() override
Update this updatable.
void begin() override
Initialize this updatable.
GenericMIDIRotaryEncoder(Enc &&encoder, MIDIAddress address, int16_t speedMultiply, uint8_t pulsesPerStep, const Sender &sender)
Construct a new MIDIRotaryEncoder.
typename std::make_signed< Enc_t >::type SignedEnc_t
A type-safe utility class for saving a MIDI address consisting of a 7-bit address,...