LCOV - code coverage report
Current view: top level - src/MIDI_Inputs/MCU - VPotRing.hpp (source / functions) Hit Total Coverage
Test: e224b347cd670555e44f06608ac41bd1ace9d9d8 Lines: 67 79 84.8 %
Date: 2020-09-08 17:44:46 Functions: 49 69 71.0 %
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           2 : inline int8_t minimum(int8_t a, int8_t b) { return a > b ? b : a; }
      13           2 : 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           5 :     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          15 :     uint8_t getPosition() const { return getPosition(getValue()); }
      33             :     /// Return the status of the center LED of the V-Pot ring.
      34          11 :     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          15 :     uint8_t getMode() const { return getMode(getValue()); }
      38             : 
      39             :     /// Get the first segment that should be on.
      40           2 :     uint8_t getStartOn() const {
      41           2 :         int8_t position = getPosition();
      42           2 :         if (position == 0)
      43           0 :             return 0;
      44           2 :         int8_t value = position - 1;
      45           2 :         switch (getMode()) {
      46           0 :             case 0: return value;
      47           2 :             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           2 :     }
      54             : 
      55             :     /// Get the first segment that should be off.
      56           2 :     uint8_t getStartOff() const {
      57           2 :         uint8_t value = getPosition();
      58           2 :         switch (getMode()) {
      59           0 :             case 0: return value;
      60           2 :             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           2 :     }
      67             : 
      68             :   private:
      69             :     virtual uint8_t getValue() const = 0;
      70             : 
      71             :     /// Extract the position from the raw value.
      72          15 :     static uint8_t getPosition(uint8_t value) {
      73          15 :         uint8_t position = value & 0x0F;
      74          15 :         return position < 0x0C ? position : 0x0B;
      75          15 :     }
      76             :     /// Extract the center LED state from the raw value.
      77          11 :     static bool getCenterLed(uint8_t value) { return value & 0x40; }
      78             :     /// Extract the mode from the raw value.
      79          15 :     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 MIDIChannelCN &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           7 :     static uint8_t sanitizeValue(uint8_t value) {
     106           7 :         return (value & 0x0F) < 0x0C ? value : ((value & 0xF0) | 0xB);
     107             :     }
     108             : 
     109             :   private:
     110           7 :     bool updateImpl(const ChannelMessageMatcher &midimsg,
     111             :                     const MIDIAddress &target) override {
     112           7 :         uint8_t index = getBankIndex(target);
     113           7 :         uint8_t value = sanitizeValue(midimsg.data2);
     114           7 :         values[index] = value;
     115           7 :         if (getSelection() == index)
     116           3 :             callback.update(*this);
     117           7 :         return true;
     118           7 :     }
     119             : 
     120          41 :     uint8_t getValue() const override { return values[getSelection()]; }
     121             : 
     122             :     /// Get the active bank selection
     123           8 :     virtual uint8_t getSelection() const { return 0; }
     124             : 
     125             :     /// Get the bank index from a MIDI address
     126           2 :     virtual setting_t getBankIndex(const MIDIAddress &target) const {
     127           2 :         (void)target;
     128           2 :         return 0;
     129             :     }
     130             : 
     131           9 :     Array<uint8_t, NumValues> values = {{}};
     132             : 
     133             :   public:
     134             :     Callback callback;
     135             : };
     136             : 
     137             : // -------------------------------------------------------------------------- //
     138             : 
     139             : /** 
     140             :  * @brief   A class for MIDI input elements that represent Mackie Control
     141             :  *          Universal V-Pots. This version is generic to allow for custom 
     142             :  *          callbacks.  
     143             :  *          This version cannot be banked.
     144             :  */
     145             : template <class Callback = VPotEmptyCallback>
     146           1 : class GenericVPotRing : public VPotRing_Base<1, Callback> {
     147             :   public:
     148           1 :     GenericVPotRing(uint8_t track, const MIDIChannelCN &channelCN,
     149             :                     const Callback &callback)
     150           1 :         : VPotRing_Base<1, Callback>{track, channelCN, callback} {}
     151             : };
     152             : 
     153             : /**
     154             :  * @brief   A class for MIDI input elements that represent Mackie Control
     155             :  *          Universal V-Pots.  
     156             :  *          This version cannot be banked.
     157             :  * @ingroup MIDIInputElements
     158             :  */
     159           1 : class VPotRing : public GenericVPotRing<> {
     160             :   public:
     161           1 :     VPotRing(uint8_t track, const MIDIChannelCN &channelCN = CHANNEL_1)
     162           1 :         : GenericVPotRing{track, channelCN, {}} {}
     163             : };
     164             : 
     165             : // -------------------------------------------------------------------------- //
     166             : 
     167             : namespace Bankable {
     168             : 
     169             : /** 
     170             :  * @brief   A class for MIDI input elements that represent Mackie Control
     171             :  *          Universal V-Pots. This version is generic to allow for custom 
     172             :  *          callbacks.  
     173             :  *          This version can be banked.
     174             :  * 
     175             :  * @tparam  NumBanks 
     176             :  *          The number of banks.
     177             :  */
     178             : template <uint8_t NumBanks, class Callback = VPotEmptyCallback>
     179           4 : class GenericVPotRing : public VPotRing_Base<NumBanks, Callback>,
     180             :                         public BankableMIDIInput<NumBanks> {
     181             :   public:
     182           4 :     GenericVPotRing(BankConfig<NumBanks> config, uint8_t track,
     183             :                     const MIDIChannelCN &channelCN, const Callback &callback)
     184           4 :         : VPotRing_Base<NumBanks, Callback>{track, channelCN, callback},
     185           8 :           BankableMIDIInput<NumBanks>{config} {}
     186             : 
     187             :   private:
     188          40 :     setting_t getSelection() const override {
     189          40 :         return BankableMIDIInput<NumBanks>::getSelection();
     190             :     };
     191             : 
     192           5 :     uint8_t getBankIndex(const MIDIAddress &target) const override {
     193           5 :         return BankableMIDIInput<NumBanks>::getBankIndex(target, this->address);
     194             :     }
     195             : 
     196             :     /// Check if the address of the incoming MIDI message is in one of the banks
     197             :     /// of this element.
     198           5 :     bool match(const MIDIAddress &target) const override {
     199          10 :         return BankableMIDIInput<NumBanks>::matchBankable(target,
     200           5 :                                                           this->address);
     201             :     }
     202             : 
     203           4 :     void onBankSettingChange() override { this->callback.update(*this); }
     204             : };
     205             : 
     206             : /** 
     207             :  * @brief   A class for MIDI input elements that represent Mackie Control
     208             :  *          Universal V-Pots.  
     209             :  *          This version can be banked.
     210             :  * 
     211             :  * @tparam  NumBanks 
     212             :  *          The number of banks.
     213             :  */
     214             : template <uint8_t NumBanks>
     215           3 : class VPotRing : public GenericVPotRing<NumBanks> {
     216             :   public:
     217           3 :     VPotRing(BankConfig<NumBanks> config, uint8_t track,
     218             :              MIDIChannelCN channelCN = CHANNEL_1)
     219           3 :         : GenericVPotRing<NumBanks>{config, track, channelCN, {}} {}
     220             : };
     221             : 
     222             : } // namespace Bankable
     223             : 
     224             : } // namespace MCU
     225             : 
     226             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-6-g40580cd