LCOV - code coverage report
Current view: top level - src/MIDI_Inputs/MCU - VPotRing.hpp (source / functions) Hit Total Coverage
Test: 90a1b9beff85a60dc6ebcea034a947a845e56960 Lines: 63 75 84.0 %
Date: 2019-11-30 15:53:32 Functions: 48 67 71.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <Banks/BankableMIDIInput.hpp>
       4             : #include <MIDI_Inputs/MIDIInputElementCC.hpp>
       5             : 
       6             : BEGIN_CS_NAMESPACE
       7             : 
       8             : namespace MCU {
       9             : 
      10             : constexpr static uint8_t VPotRingAddress = 0x30;
      11             : 
      12           1 : inline int8_t minimum(int8_t a, int8_t b) { return a > b ? b : a; }
      13           1 : inline int8_t maximum(int8_t a, int8_t b) { return a < b ? b : a; }
      14             : 
      15             : struct VPotEmptyCallback {
      16             :     VPotEmptyCallback() = default;
      17             :     template <class T>
      18           0 :     void begin(const T &) {}
      19             :     template <class T>
      20           3 :     void update(const T &) {}
      21             : };
      22             : 
      23             : /**
      24             :  * @todo    I'm terrible at naming things.
      25             :  */
      26             : class IVPotRing {
      27             :   protected:
      28           5 :     IVPotRing() = default;
      29             : 
      30             :   public:
      31             :     /// Return the position of the V-Pot ring. [0, 11]
      32          12 :     uint8_t getPosition() const { return getPosition(getValue()); }
      33             :     /// Return the status of the center LED of the V-Pot ring.
      34          10 :     bool getCenterLed() const { return getCenterLed(getValue()); }
      35             :     /// Return the mode of the V-Pot ring: 0 = single dot, 1 = boost/cut,
      36             :     /// 2 = wrap, 3 = spread
      37          12 :     uint8_t getMode() const { return getMode(getValue()); }
      38             : 
      39             :     /// Get the first segment that should be on.
      40           1 :     uint8_t getStartOn() const {
      41           1 :         int8_t position = getPosition();
      42           1 :         if (position == 0)
      43           0 :             return 0;
      44           1 :         int8_t value = position - 1;
      45           1 :         switch (getMode()) {
      46           0 :             case 0: return value;
      47           1 :             case 1: return minimum(value, 5);
      48           0 :             case 2: return 0;
      49           0 :             case 3: return maximum(5 - value, 0);
      50             :             // Shouldn't happen, just keeps the compiler happy:
      51           0 :             default: return 0;
      52             :         }
      53           1 :     }
      54             : 
      55             :     /// Get the first segment that should be off.
      56           1 :     uint8_t getStartOff() const {
      57           1 :         uint8_t value = getPosition();
      58           1 :         switch (getMode()) {
      59           0 :             case 0: return value;
      60           1 :             case 1: return maximum(value, 6);
      61           0 :             case 2: return value;
      62           0 :             case 3: return minimum(5 + value, 11);
      63             :             // Shouldn't happen, just keeps the compiler happy:
      64           0 :             default: return 0;
      65             :         }
      66           1 :     }
      67             : 
      68             :   private:
      69             :     virtual uint8_t getValue() const = 0;
      70             : 
      71             :     /// Extract the position from the raw value.
      72          12 :     static uint8_t getPosition(uint8_t value) {
      73          12 :         uint8_t position = value & 0x0F;
      74          12 :         return position < 0x0C ? position : 0x0B;
      75             :     }
      76             :     /// Extract the center LED state from the raw value.
      77          10 :     static bool getCenterLed(uint8_t value) { return value & 0x40; }
      78             :     /// Extract the mode from the raw value.
      79          12 :     static uint8_t getMode(uint8_t value) { return (value & 0x30) >> 4; }
      80             : };
      81             : 
      82             : template <uint8_t NumValues, class Callback>
      83           5 : class VPotRing_Base : public MIDIInputElementCC, public IVPotRing {
      84             :   protected:
      85           5 :     VPotRing_Base(uint8_t track, const MIDICNChannel &channelCN,
      86             :                   const Callback &callback)
      87           5 :         : MIDIInputElementCC{{track + VPotRingAddress - 1, channelCN}},
      88          20 :           callback(callback) {}
      89             : 
      90             :   public:
      91             :     /// Initialize
      92           1 :     void begin() override { callback.begin(*this); }
      93             : 
      94             :     /// Reset all values to zero
      95           0 :     void reset() override {
      96             : #ifdef VPOTRING_RESET
      97             :         values = {{}};
      98             :         callback.update(*this);
      99             : #endif
     100           0 :     }
     101             : 
     102             :   protected:
     103             :     /** Make sure that the received value is valid and will not result in array
     104             :      * out of bounds conditions. */
     105           6 :     static uint8_t sanitizeValue(uint8_t value) {
     106           6 :         return (value & 0x0F) < 0x0C ? value : ((value & 0xF0) | 0xB);
     107             :     }
     108             : 
     109             :   private:
     110           6 :     bool updateImpl(const ChannelMessageMatcher &midimsg,
     111             :                     const MIDICNChannelAddress &target) override {
     112           6 :         uint8_t index = getBankIndex(target);
     113           6 :         uint8_t value = sanitizeValue(midimsg.data2);
     114           6 :         values[index] = value;
     115           6 :         return true;
     116             :     }
     117             : 
     118          34 :     uint8_t getValue() const override { return values[getSelection()]; }
     119             : 
     120             :     /// Get the active bank selection
     121           6 :     virtual uint8_t getSelection() const { return 0; }
     122             : 
     123             :     /// Get the bank index from a MIDI address
     124           2 :     virtual setting_t getBankIndex(const MIDICNChannelAddress &target) const {
     125           2 :         (void)target;
     126           2 :         return 0;
     127             :     }
     128             : 
     129           9 :     Array<uint8_t, NumValues> values = {{}};
     130             : 
     131             :   public:
     132             :     Callback callback;
     133             : };
     134             : 
     135             : // -------------------------------------------------------------------------- //
     136             : 
     137             : /** 
     138             :  * @brief   A class for MIDI input elements that represent Mackie Control
     139             :  *          Universal V-Pots. This version is generic to allow for custom 
     140             :  *          callbacks.  
     141             :  *          This version cannot be banked.
     142             :  */
     143             : template <class Callback = VPotEmptyCallback>
     144           1 : class GenericVPotRing : public VPotRing_Base<1, Callback> {
     145             :   public:
     146           1 :     GenericVPotRing(uint8_t track, const MIDICNChannel &channelCN,
     147             :                     const Callback &callback)
     148           1 :         : VPotRing_Base<1, Callback>{track, channelCN, callback} {}
     149             : };
     150             : 
     151             : /**
     152             :  * @brief   A class for MIDI input elements that represent Mackie Control
     153             :  *          Universal V-Pots.  
     154             :  *          This version cannot be banked.
     155             :  * @ingroup MIDIInputElements
     156             :  */
     157           1 : class VPotRing : public GenericVPotRing<> {
     158             :   public:
     159           1 :     VPotRing(uint8_t track, const MIDICNChannel &channelCN = CHANNEL_1)
     160           1 :         : GenericVPotRing{track, channelCN, {}} {}
     161             : };
     162             : 
     163             : // -------------------------------------------------------------------------- //
     164             : 
     165             : namespace Bankable {
     166             : 
     167             : /** 
     168             :  * @brief   A class for MIDI input elements that represent Mackie Control
     169             :  *          Universal V-Pots. This version is generic to allow for custom 
     170             :  *          callbacks.  
     171             :  *          This version can be banked.
     172             :  * 
     173             :  * @tparam  NumBanks 
     174             :  *          The number of banks.
     175             :  */
     176             : template <uint8_t NumBanks, class Callback = VPotEmptyCallback>
     177           4 : class GenericVPotRing : public VPotRing_Base<NumBanks, Callback>,
     178             :                         public BankableMIDIInput<NumBanks> {
     179             :   public:
     180           4 :     GenericVPotRing(const BankConfig<NumBanks> &config, uint8_t track,
     181             :                     const MIDICNChannel &channelCN, const Callback &callback)
     182           4 :         : VPotRing_Base<NumBanks, Callback>{track, channelCN, callback},
     183           8 :           BankableMIDIInput<NumBanks>{config} {}
     184             : 
     185             :   private:
     186          28 :     setting_t getSelection() const override {
     187          28 :         return BankableMIDIInput<NumBanks>::getSelection();
     188             :     };
     189             : 
     190           4 :     uint8_t getBankIndex(const MIDICNChannelAddress &target) const override {
     191           4 :         return BankableMIDIInput<NumBanks>::getBankIndex(target, this->address);
     192             :     }
     193             : 
     194             :     /// Check if the address of the incoming MIDI message is in one of the banks
     195             :     /// of this element.
     196           4 :     bool match(const MIDICNChannelAddress &target) const override {
     197           8 :         return BankableMIDIInput<NumBanks>::matchBankable(target,
     198           4 :                                                           this->address);
     199             :     }
     200             : 
     201           4 :     void onBankSettingChange() override { this->callback.update(*this); }
     202             : };
     203             : 
     204             : /** 
     205             :  * @brief   A class for MIDI input elements that represent Mackie Control
     206             :  *          Universal V-Pots.  
     207             :  *          This version can be banked.
     208             :  * 
     209             :  * @tparam  NumBanks 
     210             :  *          The number of banks.
     211             :  */
     212             : template <uint8_t NumBanks>
     213           3 : class VPotRing : public GenericVPotRing<NumBanks> {
     214             :   public:
     215           3 :     VPotRing(BankConfig<NumBanks> config, uint8_t track,
     216             :              MIDICNChannel channelCN = CHANNEL_1)
     217           3 :         : GenericVPotRing<NumBanks>{config, track, channelCN, {}} {}
     218             : };
     219             : 
     220             : } // namespace Bankable
     221             : 
     222             : } // namespace MCU
     223             : 
     224             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-5-g4ff2ed6